416 lines
17 KiB
Java
416 lines
17 KiB
Java
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.applications.intentpicker;
|
|
|
|
import static android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_NONE;
|
|
import static android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_SELECTED;
|
|
import static android.content.pm.verify.domain.DomainVerificationUserState.DOMAIN_STATE_VERIFIED;
|
|
|
|
import android.app.Activity;
|
|
import android.app.settings.SettingsEnums;
|
|
import android.appwidget.AppWidgetManager;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.verify.domain.DomainVerificationManager;
|
|
import android.content.pm.verify.domain.DomainVerificationUserState;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.util.ArraySet;
|
|
import android.util.Log;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.widget.Switch;
|
|
import android.widget.TextView;
|
|
|
|
import androidx.annotation.VisibleForTesting;
|
|
import androidx.appcompat.app.AlertDialog;
|
|
import androidx.preference.Preference;
|
|
import androidx.preference.PreferenceCategory;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settings.Utils;
|
|
import com.android.settings.applications.AppInfoBase;
|
|
import com.android.settings.applications.ClearDefaultsPreference;
|
|
import com.android.settings.utils.AnnotationSpan;
|
|
import com.android.settings.widget.EntityHeaderController;
|
|
import com.android.settingslib.applications.AppUtils;
|
|
import com.android.settingslib.widget.FooterPreference;
|
|
import com.android.settingslib.widget.MainSwitchPreference;
|
|
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
|
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
|
|
/** The page of the Open by default */
|
|
public class AppLaunchSettings extends AppInfoBase implements
|
|
Preference.OnPreferenceChangeListener, OnMainSwitchChangeListener {
|
|
private static final String TAG = "AppLaunchSettings";
|
|
// Preference keys
|
|
private static final String MAIN_SWITCH_PREF_KEY = "open_by_default_supported_links";
|
|
private static final String VERIFIED_LINKS_PREF_KEY = "open_by_default_verified_links";
|
|
private static final String ADD_LINK_PREF_KEY = "open_by_default_add_link";
|
|
private static final String CLEAR_DEFAULTS_PREF_KEY = "app_launch_clear_defaults";
|
|
private static final String FOOTER_PREF_KEY = "open_by_default_footer";
|
|
|
|
private static final String MAIN_PREF_CATEGORY_KEY = "open_by_default_main_category";
|
|
private static final String SELECTED_LINKS_CATEGORY_KEY =
|
|
"open_by_default_selected_links_category";
|
|
private static final String OTHER_DETAILS_PREF_CATEGORY_KEY = "app_launch_other_defaults";
|
|
|
|
// Url and Uri
|
|
private static final String ANNOTATION_URL = "url";
|
|
private static final String LEARN_MORE_URI =
|
|
"https://developer.android.com/training/app-links/verify-site-associations";
|
|
|
|
// Dialogs id
|
|
private static final int DLG_VERIFIED_LINKS = DLG_BASE + 1;
|
|
|
|
// Arguments key
|
|
public static final String APP_PACKAGE_KEY = "app_package";
|
|
|
|
private ClearDefaultsPreference mClearDefaultsPreference;
|
|
private MainSwitchPreference mMainSwitchPreference;
|
|
private Preference mAddLinkPreference;
|
|
private PreferenceCategory mMainPreferenceCategory;
|
|
private PreferenceCategory mSelectedLinksPreferenceCategory;
|
|
private PreferenceCategory mOtherDefaultsPreferenceCategory;
|
|
|
|
private boolean mActivityCreated;
|
|
|
|
@VisibleForTesting
|
|
Context mContext;
|
|
@VisibleForTesting
|
|
DomainVerificationManager mDomainVerificationManager;
|
|
|
|
@Override
|
|
public void onAttach(Context context) {
|
|
super.onAttach(context);
|
|
mContext = context;
|
|
mActivityCreated = false;
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
addPreferencesFromResource(R.xml.installed_app_launch_settings);
|
|
mDomainVerificationManager = mContext.getSystemService(DomainVerificationManager.class);
|
|
initUIComponents();
|
|
}
|
|
|
|
@Override
|
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
|
super.onViewCreated(view, savedInstanceState);
|
|
createHeaderPreference();
|
|
}
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return SettingsEnums.APPLICATIONS_APP_LAUNCH;
|
|
}
|
|
|
|
@Override
|
|
protected AlertDialog createDialog(int id, int errorCode) {
|
|
if (id == DLG_VERIFIED_LINKS) {
|
|
return createVerifiedLinksDialog();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected boolean refreshUi() {
|
|
mClearDefaultsPreference.setPackageName(mPackageName);
|
|
mClearDefaultsPreference.setAppEntry(mAppEntry);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
final boolean isChecked = (boolean) newValue;
|
|
IntentPickerUtils.logd(
|
|
"onPreferenceChange: " + preference.getTitle() + " isChecked: " + isChecked);
|
|
if ((preference instanceof LeftSideCheckBoxPreference) && !isChecked) {
|
|
final Set<String> domainSet = new ArraySet<>();
|
|
domainSet.add(preference.getTitle().toString());
|
|
removePreference(preference.getKey());
|
|
final DomainVerificationUserState userState =
|
|
IntentPickerUtils.getDomainVerificationUserState(mDomainVerificationManager,
|
|
mPackageName);
|
|
if (userState == null) {
|
|
return false;
|
|
}
|
|
setDomainVerificationUserSelection(userState.getIdentifier(), domainSet, /* enabled= */
|
|
false);
|
|
mAddLinkPreference.setEnabled(isAddLinksNotEmpty());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
|
IntentPickerUtils.logd("onSwitchChanged: isChecked=" + isChecked);
|
|
if (mMainSwitchPreference != null) { //mMainSwitchPreference synced with Switch
|
|
mMainSwitchPreference.setChecked(isChecked);
|
|
}
|
|
if (mMainPreferenceCategory != null) {
|
|
mMainPreferenceCategory.setVisible(isChecked);
|
|
}
|
|
if (mDomainVerificationManager != null) {
|
|
try {
|
|
mDomainVerificationManager.setDomainVerificationLinkHandlingAllowed(mPackageName,
|
|
isChecked);
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
Log.w(TAG, "onSwitchChanged: " + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void createHeaderPreference() {
|
|
if (mActivityCreated) {
|
|
Log.w(TAG, "onParentActivityCreated: ignoring duplicate call.");
|
|
return;
|
|
}
|
|
mActivityCreated = true;
|
|
if (mPackageInfo == null) {
|
|
Log.w(TAG, "onParentActivityCreated: PakcageInfo is null.");
|
|
return;
|
|
}
|
|
final Activity activity = getActivity();
|
|
final String summary = activity.getString(R.string.app_launch_top_intro_message);
|
|
final Preference pref = EntityHeaderController
|
|
.newInstance(activity, this, null /* header */)
|
|
.setRecyclerView(getListView(), getSettingsLifecycle())
|
|
.setIcon(Utils.getBadgedIcon(mContext, mPackageInfo.applicationInfo))
|
|
.setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
|
|
.setSummary(summary) // add intro text
|
|
.setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo))
|
|
.setPackageName(mPackageName)
|
|
.setUid(mPackageInfo.applicationInfo.uid)
|
|
.setHasAppInfoLink(true)
|
|
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
|
|
EntityHeaderController.ActionType.ACTION_NONE)
|
|
.done(activity, getPrefContext());
|
|
getPreferenceScreen().addPreference(pref);
|
|
}
|
|
|
|
private void initUIComponents() {
|
|
initMainSwitchAndCategories();
|
|
if (canUpdateMainSwitchAndCategories()) {
|
|
initVerifiedLinksPreference();
|
|
initAddLinkPreference();
|
|
addSelectedLinksPreference();
|
|
initFooter();
|
|
}
|
|
}
|
|
|
|
private void initMainSwitchAndCategories() {
|
|
mMainSwitchPreference = (MainSwitchPreference) findPreference(MAIN_SWITCH_PREF_KEY);
|
|
mMainPreferenceCategory = findPreference(MAIN_PREF_CATEGORY_KEY);
|
|
mSelectedLinksPreferenceCategory = findPreference(SELECTED_LINKS_CATEGORY_KEY);
|
|
// Initialize the "Other Default Category" section
|
|
initOtherDefaultsSection();
|
|
}
|
|
|
|
private boolean canUpdateMainSwitchAndCategories() {
|
|
final DomainVerificationUserState userState =
|
|
IntentPickerUtils.getDomainVerificationUserState(mDomainVerificationManager,
|
|
mPackageName);
|
|
if (userState == null) {
|
|
disabledPreference();
|
|
return false;
|
|
}
|
|
|
|
IntentPickerUtils.logd("isLinkHandlingAllowed() : " + userState.isLinkHandlingAllowed());
|
|
mMainSwitchPreference.updateStatus(userState.isLinkHandlingAllowed());
|
|
mMainSwitchPreference.addOnSwitchChangeListener(this);
|
|
mMainPreferenceCategory.setVisible(userState.isLinkHandlingAllowed());
|
|
return true;
|
|
}
|
|
|
|
/** Initialize verified links preference */
|
|
private void initVerifiedLinksPreference() {
|
|
final VerifiedLinksPreference verifiedLinksPreference =
|
|
(VerifiedLinksPreference) mMainPreferenceCategory.findPreference(
|
|
VERIFIED_LINKS_PREF_KEY);
|
|
verifiedLinksPreference.setWidgetFrameClickListener(l -> {
|
|
showVerifiedLinksDialog();
|
|
});
|
|
final int verifiedLinksNo = getLinksNumber(DOMAIN_STATE_VERIFIED);
|
|
verifiedLinksPreference.setTitle(getVerifiedLinksTitle(verifiedLinksNo));
|
|
verifiedLinksPreference.setCheckBoxVisible(verifiedLinksNo > 0);
|
|
verifiedLinksPreference.setEnabled(verifiedLinksNo > 0);
|
|
}
|
|
|
|
private void showVerifiedLinksDialog() {
|
|
final int linksNo = getLinksNumber(DOMAIN_STATE_VERIFIED);
|
|
if (linksNo == 0) {
|
|
return;
|
|
}
|
|
showDialogInner(DLG_VERIFIED_LINKS, /* moveErrorCode= */ 0);
|
|
}
|
|
|
|
private AlertDialog createVerifiedLinksDialog() {
|
|
final int linksNo = getLinksNumber(DOMAIN_STATE_VERIFIED);
|
|
|
|
final View titleView = LayoutInflater.from(mContext).inflate(
|
|
R.layout.app_launch_verified_links_title, /* root= */ null);
|
|
((TextView) titleView.findViewById(R.id.dialog_title)).setText(
|
|
getVerifiedLinksTitle(linksNo));
|
|
((TextView) titleView.findViewById(R.id.dialog_message)).setText(
|
|
getVerifiedLinksMessage(linksNo));
|
|
|
|
final List<String> verifiedLinksList = IntentPickerUtils.getLinksList(
|
|
mDomainVerificationManager, mPackageName, DOMAIN_STATE_VERIFIED);
|
|
return new AlertDialog.Builder(mContext)
|
|
.setCustomTitle(titleView)
|
|
.setCancelable(true)
|
|
.setItems(verifiedLinksList.toArray(new String[0]), /* listener= */ null)
|
|
.setPositiveButton(R.string.app_launch_dialog_ok, /* listener= */ null)
|
|
.create();
|
|
}
|
|
|
|
@VisibleForTesting
|
|
String getVerifiedLinksTitle(int linksNo) {
|
|
return getResources().getQuantityString(
|
|
R.plurals.app_launch_verified_links_title, linksNo, linksNo);
|
|
}
|
|
|
|
private String getVerifiedLinksMessage(int linksNo) {
|
|
return getResources().getQuantityString(
|
|
R.plurals.app_launch_verified_links_message, linksNo, linksNo);
|
|
}
|
|
|
|
/** Add selected links items */
|
|
void addSelectedLinksPreference() {
|
|
if (getLinksNumber(DOMAIN_STATE_SELECTED) == 0) {
|
|
return;
|
|
}
|
|
mSelectedLinksPreferenceCategory.removeAll();
|
|
final List<String> selectedLinks = IntentPickerUtils.getLinksList(
|
|
mDomainVerificationManager, mPackageName, DOMAIN_STATE_SELECTED);
|
|
for (String host : selectedLinks) {
|
|
generateCheckBoxPreference(mSelectedLinksPreferenceCategory, host);
|
|
}
|
|
mAddLinkPreference.setEnabled(isAddLinksNotEmpty());
|
|
}
|
|
|
|
/** Initialize add link preference */
|
|
private void initAddLinkPreference() {
|
|
mAddLinkPreference = findPreference(ADD_LINK_PREF_KEY);
|
|
mAddLinkPreference.setVisible(isAddLinksShown());
|
|
mAddLinkPreference.setEnabled(isAddLinksNotEmpty());
|
|
mAddLinkPreference.setOnPreferenceClickListener(preference -> {
|
|
final int stateNoneLinksNo = getLinksNumber(DOMAIN_STATE_NONE);
|
|
IntentPickerUtils.logd("The number of the state none links: " + stateNoneLinksNo);
|
|
if (stateNoneLinksNo > 0) {
|
|
showProgressDialogFragment();
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
private boolean isAddLinksNotEmpty() {
|
|
return getLinksNumber(DOMAIN_STATE_NONE) > 0;
|
|
}
|
|
|
|
private boolean isAddLinksShown() {
|
|
return (isAddLinksNotEmpty() || getLinksNumber(DOMAIN_STATE_SELECTED) > 0);
|
|
}
|
|
|
|
private void showProgressDialogFragment() {
|
|
final Bundle args = new Bundle();
|
|
args.putString(APP_PACKAGE_KEY, mPackageName);
|
|
final ProgressDialogFragment dialogFragment = new ProgressDialogFragment();
|
|
dialogFragment.setArguments(args);
|
|
dialogFragment.showDialog(getActivity().getSupportFragmentManager());
|
|
}
|
|
|
|
private void disabledPreference() {
|
|
mMainSwitchPreference.updateStatus(false);
|
|
mMainSwitchPreference.setSelectable(false);
|
|
mMainSwitchPreference.setEnabled(false);
|
|
mMainPreferenceCategory.setVisible(false);
|
|
}
|
|
|
|
/** Init OTHER DEFAULTS category */
|
|
private void initOtherDefaultsSection() {
|
|
mOtherDefaultsPreferenceCategory = findPreference(OTHER_DETAILS_PREF_CATEGORY_KEY);
|
|
mOtherDefaultsPreferenceCategory.setVisible(isClearDefaultsEnabled());
|
|
mClearDefaultsPreference = (ClearDefaultsPreference) findPreference(
|
|
CLEAR_DEFAULTS_PREF_KEY);
|
|
}
|
|
|
|
private void initFooter() {
|
|
// learn more
|
|
final AnnotationSpan.LinkInfo linkInfo =
|
|
new AnnotationSpan.LinkInfo(ANNOTATION_URL, v -> {
|
|
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(LEARN_MORE_URI));
|
|
mContext.startActivity(intent);
|
|
});
|
|
final CharSequence footerText = mContext.getText(R.string.app_launch_footer);
|
|
final FooterPreference footerPreference = (FooterPreference) findPreference(
|
|
FOOTER_PREF_KEY);
|
|
footerPreference.setTitle(AnnotationSpan.linkify(footerText, linkInfo));
|
|
}
|
|
|
|
private boolean isClearDefaultsEnabled() {
|
|
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
|
|
final boolean hasBindAppWidgetPermission =
|
|
appWidgetManager.hasBindAppWidgetPermission(mAppEntry.info.packageName);
|
|
|
|
final boolean isAutoLaunchEnabled = AppUtils.hasPreferredActivities(mPm, mPackageName)
|
|
|| AppUtils.isDefaultBrowser(mContext, mPackageName)
|
|
|| AppUtils.hasUsbDefaults(mUsbManager, mPackageName);
|
|
|
|
IntentPickerUtils.logd("isClearDefaultsEnabled hasBindAppWidgetPermission : "
|
|
+ hasBindAppWidgetPermission);
|
|
IntentPickerUtils.logd(
|
|
"isClearDefaultsEnabled isAutoLaunchEnabled : " + isAutoLaunchEnabled);
|
|
return (isAutoLaunchEnabled || hasBindAppWidgetPermission);
|
|
}
|
|
|
|
private void setDomainVerificationUserSelection(UUID identifier, Set<String> domainSet,
|
|
boolean isEnabled) {
|
|
try {
|
|
mDomainVerificationManager.setDomainVerificationUserSelection(identifier, domainSet,
|
|
isEnabled);
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
Log.w(TAG, "addSelectedItems : " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
private void generateCheckBoxPreference(PreferenceCategory parent, String title) {
|
|
final LeftSideCheckBoxPreference checkBoxPreference = new LeftSideCheckBoxPreference(
|
|
parent.getContext(), /* isChecked= */ true);
|
|
checkBoxPreference.setTitle(title);
|
|
checkBoxPreference.setOnPreferenceChangeListener(this);
|
|
checkBoxPreference.setKey(UUID.randomUUID().toString());
|
|
parent.addPreference(checkBoxPreference);
|
|
}
|
|
|
|
/** get the number of the specify links */
|
|
private int getLinksNumber(@DomainVerificationUserState.DomainState int state) {
|
|
final List<String> linkList = IntentPickerUtils.getLinksList(
|
|
mDomainVerificationManager, mPackageName, state);
|
|
if (linkList == null) {
|
|
return 0;
|
|
}
|
|
return linkList.size();
|
|
}
|
|
}
|