1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.settings.applications; 17 18 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; 19 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; 20 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; 21 22 import android.app.settings.SettingsEnums; 23 import android.content.pm.PackageManager; 24 import android.os.Bundle; 25 import android.text.TextUtils; 26 import android.util.ArraySet; 27 import android.util.Log; 28 import android.view.View; 29 30 import androidx.annotation.VisibleForTesting; 31 import androidx.appcompat.app.AlertDialog; 32 import androidx.preference.PreferenceCategory; 33 34 import com.android.settings.R; 35 import com.android.settings.Utils; 36 import com.android.settingslib.widget.FooterPreference; 37 import com.android.settingslib.widget.RadioButtonPreference; 38 39 /** 40 * Display the Open Supported Links page. Allow users choose what kind supported links they need. 41 */ 42 public class OpenSupportedLinks extends AppInfoWithHeader implements 43 RadioButtonPreference.OnClickListener { 44 private static final String TAG = "OpenSupportedLinks"; 45 private static final String RADIO_GROUP_KEY = "supported_links_radio_group"; 46 private static final String FOOTER_KEY = "supported_links_footer"; 47 private static final String KEY_LINK_OPEN_ALWAYS = "app_link_open_always"; 48 private static final String KEY_LINK_OPEN_ASK = "app_link_open_ask"; 49 private static final String KEY_LINK_OPEN_NEVER = "app_link_open_never"; 50 51 private static final int ALLOW_ALWAYS_OPENING = 0; 52 private static final int ASK_EVERY_TIME = 1; 53 private static final int NOT_ALLOWED_OPENING = 2; 54 55 private int mCurrentIndex; 56 private String[] mRadioKeys = {KEY_LINK_OPEN_ALWAYS, KEY_LINK_OPEN_ASK, KEY_LINK_OPEN_NEVER}; 57 58 @VisibleForTesting 59 PackageManager mPackageManager; 60 @VisibleForTesting 61 PreferenceCategory mPreferenceCategory; 62 @VisibleForTesting 63 RadioButtonPreference mAllowOpening; 64 @VisibleForTesting 65 RadioButtonPreference mAskEveryTime; 66 @VisibleForTesting 67 RadioButtonPreference mNotAllowed; 68 69 @Override onCreate(Bundle savedInstanceState)70 public void onCreate(Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 mPackageManager = getPackageManager(); 73 addPreferencesFromResource(R.xml.open_supported_links); 74 initRadioPreferencesGroup(); 75 updateFooterPreference(); 76 } 77 78 @Override getMetricsCategory()79 public int getMetricsCategory() { 80 return SettingsEnums.OPEN_SUPPORTED_LINKS; 81 } 82 83 /** 84 * Here to handle radio group and generate the radios. 85 */ 86 @VisibleForTesting initRadioPreferencesGroup()87 void initRadioPreferencesGroup() { 88 mPreferenceCategory = findPreference(RADIO_GROUP_KEY); 89 mAllowOpening = makeRadioPreference(KEY_LINK_OPEN_ALWAYS, R.string.app_link_open_always); 90 final int entriesNo = getEntriesNo(); 91 //This to avoid the summary line wrap 92 mAllowOpening.setAppendixVisibility(View.GONE); 93 mAllowOpening.setSummary(getResources().getQuantityString( 94 R.plurals.app_link_open_always_summary, entriesNo, entriesNo)); 95 mAskEveryTime = makeRadioPreference(KEY_LINK_OPEN_ASK, R.string.app_link_open_ask); 96 mNotAllowed = makeRadioPreference(KEY_LINK_OPEN_NEVER, R.string.app_link_open_never); 97 98 final int state = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, mUserId); 99 mCurrentIndex = linkStateToIndex(state); 100 setRadioStatus(mCurrentIndex); 101 } 102 103 @Override onRadioButtonClicked(RadioButtonPreference preference)104 public void onRadioButtonClicked(RadioButtonPreference preference) { 105 final int clickedIndex = preferenceKeyToIndex(preference.getKey()); 106 if (mCurrentIndex != clickedIndex) { 107 mCurrentIndex = clickedIndex; 108 setRadioStatus(mCurrentIndex); 109 updateAppLinkState(indexToLinkState(mCurrentIndex)); 110 } 111 } 112 makeRadioPreference(String key, int stringId)113 private RadioButtonPreference makeRadioPreference(String key, int stringId) { 114 final RadioButtonPreference pref = new RadioButtonPreference( 115 mPreferenceCategory.getContext()); 116 pref.setKey(key); 117 pref.setTitle(stringId); 118 pref.setOnClickListener(this); 119 mPreferenceCategory.addPreference(pref); 120 return pref; 121 } 122 123 @VisibleForTesting getEntriesNo()124 int getEntriesNo() { 125 return Utils.getHandledDomains(mPackageManager, mPackageName).size(); 126 } 127 linkStateToIndex(int state)128 private int linkStateToIndex(int state) { 129 switch (state) { 130 case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: 131 return ALLOW_ALWAYS_OPENING; 132 case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: 133 return NOT_ALLOWED_OPENING; 134 default: 135 return ASK_EVERY_TIME; 136 } 137 } 138 indexToLinkState(int index)139 private int indexToLinkState(int index) { 140 switch (index) { 141 case 0: 142 return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; 143 case 2: 144 return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; 145 default: 146 return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; 147 } 148 } 149 setRadioStatus(int index)150 private void setRadioStatus(int index) { 151 mAllowOpening.setChecked(index == ALLOW_ALWAYS_OPENING); 152 mAskEveryTime.setChecked(index == ASK_EVERY_TIME); 153 mNotAllowed.setChecked(index == NOT_ALLOWED_OPENING); 154 } 155 preferenceKeyToIndex(String key)156 private int preferenceKeyToIndex(String key) { 157 for (int i = 0; i < mRadioKeys.length; i++) { 158 if (TextUtils.equals(key, mRadioKeys[i])) { 159 return i; 160 } 161 } 162 return ASK_EVERY_TIME; 163 } 164 updateAppLinkState(final int newState)165 private void updateAppLinkState(final int newState) { 166 final int priorState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, 167 mUserId); 168 169 if (priorState == newState) { 170 return; 171 } 172 173 final boolean success = mPackageManager.updateIntentVerificationStatusAsUser(mPackageName, 174 newState, mUserId); 175 if (success) { 176 // Read back the state to see if the change worked 177 final int updatedState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, 178 mUserId); 179 } else { 180 Log.e(TAG, "Couldn't update intent verification status!"); 181 } 182 } 183 184 /** 185 * Here is handle the Footer. 186 */ updateFooterPreference()187 private void updateFooterPreference() { 188 final FooterPreference footer = findPreference(FOOTER_KEY); 189 if (footer == null) { 190 Log.w(TAG, "Can't find the footer preference."); 191 return; 192 } 193 addLinksToFooter(footer); 194 } 195 196 @VisibleForTesting addLinksToFooter(FooterPreference footer)197 void addLinksToFooter(FooterPreference footer) { 198 final ArraySet<String> result = Utils.getHandledDomains(mPackageManager, mPackageName); 199 if (result.isEmpty()) { 200 Log.w(TAG, "Can't find any app links."); 201 return; 202 } 203 CharSequence title = footer.getTitle() + System.lineSeparator(); 204 for (String link : result) { 205 title = title + System.lineSeparator() + link; 206 } 207 footer.setTitle(title); 208 } 209 210 @Override refreshUi()211 protected boolean refreshUi() { 212 return true; 213 } 214 215 @Override createDialog(int id, int errorCode)216 protected AlertDialog createDialog(int id, int errorCode) { 217 return null; 218 } 219 } 220