Implement new "Open by default" page
- Use the new MainSwitch and TopIntro widgets. - Create VerifiedLinksPreference and LeftSideCheckBoxPreference. - Create ProgressDialogFragment and SupportedLinksDialogFragment. - Retrieve the links info from DomainVerificationManager. - Allow user to change the supported links into selected links. - Refactor the ClearDefaultsPreference. - Move AppLaunchSettings into intentpicker directory. Bug: 177923646 Bug: 182530528 Test: manual test Change-Id: I935a2fdd0f62cdb8b8d3210fb2f800f682249cb7
This commit is contained in:
25
res/layout/app_launch_progress.xml
Normal file
25
res/layout/app_launch_progress.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<ProgressBar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:id="@+id/scan_links_progressbar"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
49
res/layout/app_launch_verified_links_title.xml
Normal file
49
res/layout/app_launch_verified_links_title.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:paddingStart="?android:attr/dialogPreferredPadding"
|
||||
android:paddingEnd="?android:attr/dialogPreferredPadding"
|
||||
android:paddingTop="@*android:dimen/dialog_padding_top_material">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_title"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
style="?android:attr/windowTitleStyle" />
|
||||
|
||||
<TextView
|
||||
android:paddingTop="12dp"
|
||||
android:id="@+id/dialog_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance.DialogMessage" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
28
res/layout/preference_widget_info.xml
Normal file
28
res/layout/preference_widget_info.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<ImageView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/settings_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_info_outline_24"
|
||||
android:contentDescription="@string/settings_button" />
|
31
res/layout/supported_links_dialog_item.xml
Normal file
31
res/layout/supported_links_dialog_item.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<CheckedTextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:textColor="?android:attr/textColorAlertDialogListItem"
|
||||
android:drawableLeft="?android:attr/listChoiceIndicatorMultiple" />
|
||||
|
25
res/layout/verified_links_widget.xml
Normal file
25
res/layout/verified_links_widget.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include layout="@layout/preference_widget_info"
|
||||
android:id="@+id/verified_links_widget" />
|
||||
</LinearLayout>
|
@@ -16,31 +16,59 @@
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/launch_by_default">
|
||||
|
||||
<PreferenceCategory android:key="app_launch_domain_links"
|
||||
android:title="@string/app_launch_domain_links_title">
|
||||
<com.android.settingslib.widget.MainSwitchPreference
|
||||
android:key="open_by_default_supported_links"
|
||||
android:title="@string/app_launch_open_domain_urls_title"/>
|
||||
|
||||
<Preference
|
||||
android:key="app_link_state"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:title="@string/app_launch_open_domain_urls_title"/>
|
||||
<com.android.settingslib.widget.TopIntroPreference
|
||||
android:key="open_by_default_top_intro"
|
||||
android:title="@string/app_launch_top_intro_message"/>
|
||||
|
||||
<com.android.settings.applications.AppDomainsPreference
|
||||
android:key="app_launch_supported_domain_urls"
|
||||
android:title="@string/app_launch_supported_domain_urls_title"
|
||||
android:dependency="app_link_state"
|
||||
/>
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/preference_category_no_label"
|
||||
android:key="open_by_default_main_category"
|
||||
settings:searchable="false">
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/app_launch_links_category">
|
||||
|
||||
<com.android.settings.applications.intentpicker.VerifiedLinksPreference
|
||||
android:key="open_by_default_verified_links"
|
||||
android:title="@string/summary_placeholder"
|
||||
android:order="-100"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/preference_category_no_label"
|
||||
android:key="open_by_default_selected_links_category"
|
||||
android:order="100"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<Preference
|
||||
android:key="open_by_default_add_link"
|
||||
android:title="@string/app_launch_add_link"
|
||||
android:order="300"
|
||||
android:icon="@drawable/ic_add_24dp"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:key="app_launch_other_defaults"
|
||||
android:title="@string/app_launch_other_defaults_title">
|
||||
|
||||
<com.android.settings.applications.ClearDefaultsPreference
|
||||
android:key="app_launch_clear_defaults"
|
||||
android:selectable="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="open_by_default_footer"
|
||||
android:selectable="false"
|
||||
settings:allowDividerAbove="true"
|
||||
settings:searchable="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:key="app_launch_other_defaults"
|
||||
android:title="@string/app_launch_other_defaults_title">
|
||||
|
||||
<com.android.settings.applications.ClearDefaultsPreference
|
||||
android:key="app_launch_clear_defaults"
|
||||
android:selectable="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settingslib.applications.AppUtils;
|
||||
|
||||
public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListener,
|
||||
Preference.OnPreferenceChangeListener {
|
||||
private static final String TAG = "AppLaunchSettings";
|
||||
private static final String KEY_APP_LINK_STATE = "app_link_state";
|
||||
private static final String KEY_SUPPORTED_DOMAIN_URLS = "app_launch_supported_domain_urls";
|
||||
private static final String KEY_CLEAR_DEFAULTS = "app_launch_clear_defaults";
|
||||
private static final String FRAGMENT_OPEN_SUPPORTED_LINKS =
|
||||
"com.android.settings.applications.OpenSupportedLinks";
|
||||
|
||||
private PackageManager mPm;
|
||||
|
||||
private boolean mIsBrowser;
|
||||
private boolean mHasDomainUrls;
|
||||
private Preference mAppLinkState;
|
||||
private AppDomainsPreference mAppDomainUrls;
|
||||
private ClearDefaultsPreference mClearDefaultsPreference;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
addPreferencesFromResource(R.xml.installed_app_launch_settings);
|
||||
mAppDomainUrls = (AppDomainsPreference) findPreference(KEY_SUPPORTED_DOMAIN_URLS);
|
||||
mClearDefaultsPreference = (ClearDefaultsPreference) findPreference(KEY_CLEAR_DEFAULTS);
|
||||
mAppLinkState = findPreference(KEY_APP_LINK_STATE);
|
||||
mAppLinkState.setOnPreferenceClickListener(preference -> {
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(ARG_PACKAGE_NAME, mPackageName);
|
||||
args.putInt(ARG_PACKAGE_UID, mUserId);
|
||||
|
||||
new SubSettingLauncher(this.getContext())
|
||||
.setDestination(FRAGMENT_OPEN_SUPPORTED_LINKS)
|
||||
.setArguments(args)
|
||||
.setSourceMetricsCategory(SettingsEnums.APPLICATIONS_APP_LAUNCH)
|
||||
.setTitleRes(-1)
|
||||
.launch();
|
||||
return true;
|
||||
});
|
||||
|
||||
mPm = getActivity().getPackageManager();
|
||||
|
||||
mIsBrowser = AppUtils.isBrowserApp(this.getContext(), mPackageName, UserHandle.myUserId());
|
||||
mHasDomainUrls =
|
||||
(mAppEntry.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
|
||||
|
||||
if (!mIsBrowser) {
|
||||
CharSequence[] entries = getEntries(mPackageName);
|
||||
mAppDomainUrls.setTitles(entries);
|
||||
mAppDomainUrls.setValues(new int[entries.length]);
|
||||
mAppLinkState.setEnabled(mHasDomainUrls);
|
||||
} else {
|
||||
// Browsers don't show the app-link prefs
|
||||
mAppLinkState.setShouldDisableView(true);
|
||||
mAppLinkState.setEnabled(false);
|
||||
mAppDomainUrls.setShouldDisableView(true);
|
||||
mAppDomainUrls.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private int linkStateToResourceId(int state) {
|
||||
switch (state) {
|
||||
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
|
||||
return R.string.app_link_open_always; // Always
|
||||
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER:
|
||||
return R.string.app_link_open_never; // Never
|
||||
default:
|
||||
return R.string.app_link_open_ask; // Ask
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence[] getEntries(String packageName) {
|
||||
ArraySet<String> result = Utils.getHandledDomains(mPm, packageName);
|
||||
return result.toArray(new CharSequence[result.size()]);
|
||||
}
|
||||
|
||||
private void setAppLinkStateSummary() {
|
||||
final int state = mPm.getIntentVerificationStatusAsUser(mPackageName,
|
||||
UserHandle.myUserId());
|
||||
mAppLinkState.setSummary(linkStateToResourceId(state));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean refreshUi() {
|
||||
if (mHasDomainUrls) {
|
||||
//Update the summary after return from the OpenSupportedLinks
|
||||
setAppLinkStateSummary();
|
||||
}
|
||||
mClearDefaultsPreference.setPackageName(mPackageName);
|
||||
mClearDefaultsPreference.setAppEntry(mAppEntry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlertDialog createDialog(int id, int errorCode) {
|
||||
// No dialogs for preferred launch settings.
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
// actual updates are handled by the app link dropdown callback
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.APPLICATIONS_APP_LAUNCH;
|
||||
}
|
||||
}
|
@@ -117,7 +117,7 @@ public class ClearDefaultsPreference extends Preference {
|
||||
if (mUsbManager != null) {
|
||||
final int userId = UserHandle.myUserId();
|
||||
mPm.clearPackagePreferredActivities(mPackageName);
|
||||
if (isDefaultBrowser(mPackageName)) {
|
||||
if (AppUtils.isDefaultBrowser(getContext(), mPackageName)) {
|
||||
mPm.setDefaultBrowserPackageNameAsUser(null, userId);
|
||||
}
|
||||
try {
|
||||
@@ -141,7 +141,7 @@ public class ClearDefaultsPreference extends Preference {
|
||||
|
||||
TextView autoLaunchView = (TextView) view.findViewById(R.id.auto_launch);
|
||||
boolean autoLaunchEnabled = AppUtils.hasPreferredActivities(mPm, mPackageName)
|
||||
|| isDefaultBrowser(mPackageName)
|
||||
|| AppUtils.isDefaultBrowser(getContext(), mPackageName)
|
||||
|| AppUtils.hasUsbDefaults(mUsbManager, mPackageName);
|
||||
if (!autoLaunchEnabled && !hasBindAppWidgetPermission) {
|
||||
resetLaunchDefaultsUi(autoLaunchView);
|
||||
@@ -185,11 +185,6 @@ public class ClearDefaultsPreference extends Preference {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isDefaultBrowser(String packageName) {
|
||||
final String defaultBrowser = mPm.getDefaultBrowserPackageNameAsUser(UserHandle.myUserId());
|
||||
return packageName.equals(defaultBrowser);
|
||||
}
|
||||
|
||||
private void resetLaunchDefaultsUi(TextView autoLaunchView) {
|
||||
autoLaunchView.setText(R.string.auto_launch_disable_text);
|
||||
// Disable clear activities button
|
||||
|
@@ -19,6 +19,7 @@ package com.android.settings.applications;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.applications.intentpicker.AppLaunchSettings;
|
||||
|
||||
public class InstalledAppOpenByDefaultActivity extends SettingsActivity {
|
||||
|
||||
|
@@ -28,7 +28,7 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.applications.AppLaunchSettings;
|
||||
import com.android.settings.applications.intentpicker.AppLaunchSettings;
|
||||
import com.android.settingslib.applications.AppUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
|
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* 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 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);
|
||||
}
|
||||
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 Preference pref = EntityHeaderController
|
||||
.newInstance(activity, this, null /* header */)
|
||||
.setRecyclerView(getListView(), getSettingsLifecycle())
|
||||
.setIcon(Utils.getBadgedIcon(mContext, mPackageInfo.applicationInfo))
|
||||
.setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
|
||||
.setSummary("" /* summary */) // no version number
|
||||
.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();
|
||||
addSelectedLinksPreference();
|
||||
initAddLinkPreference();
|
||||
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 */
|
||||
public 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);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize add link preference */
|
||||
private void initAddLinkPreference() {
|
||||
final Preference addLinkPreference = findPreference(ADD_LINK_PREF_KEY);
|
||||
if (addLinkPreference != null) {
|
||||
addLinkPreference.setEnabled(getLinksNumber(DOMAIN_STATE_NONE) > 0);
|
||||
addLinkPreference.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 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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.content.pm.PackageManager;
|
||||
import android.content.pm.verify.domain.DomainVerificationManager;
|
||||
import android.content.pm.verify.domain.DomainVerificationUserState;
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.AlignmentSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** The common APIs for intent picker */
|
||||
public class IntentPickerUtils {
|
||||
private static final String TAG = "IntentPickerUtils";
|
||||
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
|
||||
|
||||
private IntentPickerUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the centralized title.
|
||||
*
|
||||
* @param title The title of the dialog box.
|
||||
* @return The spannable string with centralized title.
|
||||
*/
|
||||
public static SpannableString getCentralizedDialogTitle(String title) {
|
||||
final SpannableString dialogTitle = new SpannableString(title);
|
||||
dialogTitle.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), /* start= */
|
||||
0, title.length(), /* flags= */ 0);
|
||||
return dialogTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link DomainVerificationUserState} for specific application.
|
||||
*
|
||||
* @param manager The {@link DomainVerificationManager}.
|
||||
* @param pkgName The package name of the target application.
|
||||
*/
|
||||
public static DomainVerificationUserState getDomainVerificationUserState(
|
||||
DomainVerificationManager manager, String pkgName) {
|
||||
try {
|
||||
final DomainVerificationUserState domainVerificationUserState =
|
||||
manager.getDomainVerificationUserState(pkgName);
|
||||
return domainVerificationUserState;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the links list by {@link DomainVerificationUserState.DomainState}
|
||||
*
|
||||
* @param manager The {@link DomainVerificationManager}.
|
||||
* @param pkgName The package name of the target application.
|
||||
* @param state The user state you want to query.
|
||||
* @return A links list.
|
||||
*/
|
||||
public static List<String> getLinksList(DomainVerificationManager manager, String pkgName,
|
||||
@DomainVerificationUserState.DomainState int state) {
|
||||
final DomainVerificationUserState userStage = getDomainVerificationUserState(manager,
|
||||
pkgName);
|
||||
if (userStage == null) {
|
||||
return null;
|
||||
}
|
||||
return userStage.getHostToStateMap()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(it -> it.getValue() == state)
|
||||
.map(it -> it.getKey())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/** Logs the message in debug ROM. */
|
||||
public static void logd(String msg) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.widget.TwoTargetPreference;
|
||||
|
||||
/** This preference has a check box in the left side. */
|
||||
public class LeftSideCheckBoxPreference extends TwoTargetPreference {
|
||||
private boolean mChecked;
|
||||
private CheckBox mCheckBox;
|
||||
|
||||
public LeftSideCheckBoxPreference(Context context, AttributeSet attrs,
|
||||
int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setLayoutResource(R.layout.preference_checkable_two_target);
|
||||
}
|
||||
|
||||
public LeftSideCheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public LeftSideCheckBoxPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public LeftSideCheckBoxPreference(Context context) {
|
||||
this(context, /* attrs= */ null);
|
||||
}
|
||||
|
||||
public LeftSideCheckBoxPreference(Context context, boolean isChecked) {
|
||||
super(context);
|
||||
mChecked = isChecked;
|
||||
setLayoutResource(R.layout.preference_checkable_two_target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder view) {
|
||||
super.onBindViewHolder(view);
|
||||
mCheckBox = (CheckBox) view.findViewById(com.android.internal.R.id.checkbox);
|
||||
if (mCheckBox != null) {
|
||||
mCheckBox.setChecked(mChecked);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
if (mCheckBox != null) {
|
||||
mChecked = !mChecked;
|
||||
mCheckBox.setChecked(mChecked);
|
||||
callChangeListener(mChecked);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.verify.domain.DomainOwner;
|
||||
import android.content.pm.verify.domain.DomainVerificationManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** A customized {@link DialogFragment} with a progress bar. */
|
||||
public class ProgressDialogFragment extends DialogFragment {
|
||||
private static final String TAG = "ProgressDialogFragment";
|
||||
private static final String DLG_ID = "ProgressDialog";
|
||||
private static final int PROGRESS_BAR_STEPPING_TIME = 20;
|
||||
|
||||
private ProgressAlertDialog mProgressAlertDialog;
|
||||
private DomainVerificationManager mDomainVerificationManager;
|
||||
private List<SupportedLinkWrapper> mSupportedLinkWrapperList;
|
||||
private SupportedLinkViewModel mViewModel;
|
||||
private Handler mHandle;
|
||||
private String mPackage;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mViewModel = ViewModelProviders.of(this.getActivity()).get(SupportedLinkViewModel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
mPackage = getArguments().getString(AppLaunchSettings.APP_PACKAGE_KEY);
|
||||
mDomainVerificationManager = getActivity().getSystemService(
|
||||
DomainVerificationManager.class);
|
||||
mHandle = new Handler(Looper.getMainLooper());
|
||||
mProgressAlertDialog = createProgressAlertDialog();
|
||||
return mProgressAlertDialog;
|
||||
}
|
||||
|
||||
private ProgressAlertDialog createProgressAlertDialog() {
|
||||
final Context context = getActivity();
|
||||
final ProgressAlertDialog progressDialog = new ProgressAlertDialog(context);
|
||||
final String title = context.getResources().getString(
|
||||
R.string.app_launch_checking_links_title);
|
||||
progressDialog.setTitle(IntentPickerUtils.getCentralizedDialogTitle(title));
|
||||
progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
|
||||
context.getText(R.string.app_launch_dialog_cancel),
|
||||
(dialog, which) -> {
|
||||
if (which == DialogInterface.BUTTON_NEGATIVE) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
progressDialog.setCanceledOnTouchOutside(true);
|
||||
return progressDialog;
|
||||
}
|
||||
|
||||
/** Display the {@link ProgressAlertDialog}. */
|
||||
public void showDialog(FragmentManager manager) {
|
||||
show(manager, DLG_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
generateProgressAlertDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mProgressAlertDialog != null && mProgressAlertDialog.isShowing()) {
|
||||
mProgressAlertDialog.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To generate a progress alter dialog and invoke the supported links dialog.
|
||||
*/
|
||||
private void generateProgressAlertDialog() {
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
final long start = SystemClock.elapsedRealtime();
|
||||
queryLinksInBackground();
|
||||
IntentPickerUtils.logd(
|
||||
"queryLinksInBackground take time: " + (SystemClock.elapsedRealtime() - start));
|
||||
if (mProgressAlertDialog.isShowing()) {
|
||||
mHandle.post(() -> {
|
||||
synchronized (mHandle) {
|
||||
if (mProgressAlertDialog.isShowing()) {
|
||||
mProgressAlertDialog.dismiss();
|
||||
IntentPickerUtils.logd("mProgressAlertDialog.dismiss() and isShowing: "
|
||||
+ mProgressAlertDialog.isShowing());
|
||||
launchSupportedLinksDialogFragment();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void queryLinksInBackground() {
|
||||
final List<String> links = IntentPickerUtils.getLinksList(mDomainVerificationManager,
|
||||
mPackage, DOMAIN_STATE_NONE);
|
||||
final int linksNo = links.size();
|
||||
int index = 0;
|
||||
mSupportedLinkWrapperList = new ArrayList<>();
|
||||
for (String host : links) {
|
||||
final List<DomainOwner> ownerList =
|
||||
mDomainVerificationManager.getOwnersForDomain(host);
|
||||
mSupportedLinkWrapperList.add(new SupportedLinkWrapper(getActivity(), host, ownerList));
|
||||
index++;
|
||||
// The cancel was clicked while progressing to collect data.
|
||||
if (!mProgressAlertDialog.isShowing()) {
|
||||
Log.w(TAG, "Exit the background thread!!!");
|
||||
// clear buffer
|
||||
mSupportedLinkWrapperList.clear();
|
||||
break;
|
||||
}
|
||||
int progress = (int) (index * 100) / linksNo;
|
||||
mHandle.post(() -> {
|
||||
synchronized (mHandle) {
|
||||
if (!mProgressAlertDialog.isShowing()) {
|
||||
Log.w(TAG, "Exit the UI thread");
|
||||
return;
|
||||
}
|
||||
mProgressAlertDialog.getProgressBar().setProgress(progress);
|
||||
}
|
||||
});
|
||||
if (ownerList.size() == 0) {
|
||||
SystemClock.sleep(PROGRESS_BAR_STEPPING_TIME);
|
||||
}
|
||||
}
|
||||
IntentPickerUtils.logd("queryLinksInBackground : SupportedLinkWrapperList size="
|
||||
+ mSupportedLinkWrapperList.size());
|
||||
Collections.sort(mSupportedLinkWrapperList);
|
||||
}
|
||||
|
||||
private void launchSupportedLinksDialogFragment() {
|
||||
if (mSupportedLinkWrapperList.size() > 0) {
|
||||
mViewModel.setSupportedLinkWrapperList(mSupportedLinkWrapperList);
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(AppLaunchSettings.APP_PACKAGE_KEY, mPackage);
|
||||
final SupportedLinksDialogFragment dialogFragment = new SupportedLinksDialogFragment();
|
||||
dialogFragment.setArguments(args);
|
||||
dialogFragment.showDialog(getActivity().getSupportFragmentManager());
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a custom {@link AlertDialog} with a {@link ProgressBar}. */
|
||||
static class ProgressAlertDialog extends AlertDialog {
|
||||
private ProgressBar mProgressBar;
|
||||
|
||||
protected ProgressAlertDialog(@NonNull Context context) {
|
||||
this(context, 0);
|
||||
}
|
||||
|
||||
protected ProgressAlertDialog(@NonNull Context context, int themeResId) {
|
||||
super(context, themeResId);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
final View view = LayoutInflater.from(context).inflate(
|
||||
R.layout.app_launch_progress, /* root= */ null);
|
||||
mProgressBar = view.findViewById(R.id.scan_links_progressbar);
|
||||
mProgressBar.setProgress(0);
|
||||
mProgressBar.setMax(100);
|
||||
setView(view);
|
||||
}
|
||||
|
||||
ProgressBar getProgressBar() {
|
||||
return mProgressBar;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.app.Application;
|
||||
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This {@link AndroidViewModel} provides supported link wrapper data
|
||||
* between multiple fragments.
|
||||
*/
|
||||
public class SupportedLinkViewModel extends AndroidViewModel {
|
||||
private List<SupportedLinkWrapper> mSupportedLinkWrapperList;
|
||||
|
||||
public SupportedLinkViewModel(Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
/** Clear the list buffer of the {@link SupportedLinkWrapper}. */
|
||||
public void clearSupportedLinkWrapperList() {
|
||||
mSupportedLinkWrapperList = new ArrayList<>();
|
||||
}
|
||||
|
||||
/** Set the list buffer of the {@link SupportedLinkWrapper}. */
|
||||
public void setSupportedLinkWrapperList(List<SupportedLinkWrapper> wrapperList) {
|
||||
mSupportedLinkWrapperList = wrapperList;
|
||||
}
|
||||
|
||||
/** Get the list buffer of the {@link SupportedLinkWrapper}. */
|
||||
public List<SupportedLinkWrapper> getSupportedLinkWrapperList() {
|
||||
return mSupportedLinkWrapperList;
|
||||
}
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.verify.domain.DomainOwner;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A buffer of the supported link data. This {@link SupportedLinkWrapper} wraps the host, enabled
|
||||
* and a list of {@link DomainOwner}.
|
||||
*/
|
||||
public class SupportedLinkWrapper implements Comparable {
|
||||
private static final String TAG = "SupportedLinkWrapper";
|
||||
|
||||
private String mHost;
|
||||
private List<DomainOwner> mOwnerList;
|
||||
private boolean mIsEnabled;
|
||||
private String mLastOwnerName;
|
||||
private boolean mIsChecked;
|
||||
|
||||
public SupportedLinkWrapper(Context context, String host, List<DomainOwner> ownerList) {
|
||||
mHost = host;
|
||||
mOwnerList = ownerList;
|
||||
mIsEnabled = true;
|
||||
mLastOwnerName = "";
|
||||
mIsChecked = false;
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
if (mOwnerList.size() > 0) {
|
||||
final long nonOverirideableNo = mOwnerList.stream()
|
||||
.filter(it -> !it.isOverrideable())
|
||||
.count();
|
||||
mIsEnabled = (nonOverirideableNo == 0L);
|
||||
if (nonOverirideableNo > 0L) {
|
||||
mLastOwnerName = getLastPackageLabel(context, false);
|
||||
} else {
|
||||
mLastOwnerName = getLastPackageLabel(context, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getLastPackageLabel(Context context, boolean isOverrideable) {
|
||||
final List<String> labelList = mOwnerList.stream()
|
||||
.filter(it -> it.isOverrideable() == isOverrideable)
|
||||
.map(it -> getLabel(context, it.getPackageName()))
|
||||
.filter(label -> label != null)
|
||||
.collect(Collectors.toList());
|
||||
return labelList.get(labelList.size() - 1);
|
||||
}
|
||||
|
||||
private String getLabel(Context context, String pkg) {
|
||||
try {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
return pm.getApplicationInfo(pkg, /* flags= */ 0).loadLabel(pm).toString();
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "getLabel error : " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the enabled/disabled value for list item. */
|
||||
public boolean isEnabled() {
|
||||
return mIsEnabled;
|
||||
}
|
||||
|
||||
/** Returns the display format of list item in the Supported Links dialog */
|
||||
public String getDisplayTitle(Context context) {
|
||||
if (TextUtils.isEmpty(mLastOwnerName) || context == null) {
|
||||
return mHost;
|
||||
}
|
||||
return mHost + System.lineSeparator() + context.getString(
|
||||
R.string.app_launch_supported_links_subtext, mLastOwnerName);
|
||||
}
|
||||
|
||||
/** Returns the host name. */
|
||||
public String getHost() {
|
||||
return mHost;
|
||||
}
|
||||
|
||||
/** Returns the checked value for list item. */
|
||||
public boolean isChecked() {
|
||||
return mIsChecked;
|
||||
}
|
||||
|
||||
/** Set the checked value. */
|
||||
public void setChecked(boolean isChecked) {
|
||||
mIsChecked = isChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
final SupportedLinkWrapper that = (SupportedLinkWrapper) o;
|
||||
if (this.mIsEnabled != that.mIsEnabled) {
|
||||
return this.mIsEnabled ? -1 : 1;
|
||||
}
|
||||
if (TextUtils.isEmpty(this.mLastOwnerName) != TextUtils.isEmpty(that.mLastOwnerName)) {
|
||||
return TextUtils.isEmpty(this.mLastOwnerName) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.CheckedTextView;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** This adapter is for supported links dialog. */
|
||||
public class SupportedLinksAdapter extends BaseAdapter {
|
||||
private final Context mContext;
|
||||
private final List<SupportedLinkWrapper> mWrapperList;
|
||||
|
||||
public SupportedLinksAdapter(Context context, List<SupportedLinkWrapper> list) {
|
||||
mContext = context;
|
||||
mWrapperList = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mWrapperList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
if (position < mWrapperList.size()) {
|
||||
return mWrapperList.get(position);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.supported_links_dialog_item, /* root= */ null);
|
||||
}
|
||||
final CheckedTextView textView = convertView.findViewById(android.R.id.text1);
|
||||
textView.setText(mWrapperList.get(position).getDisplayTitle(mContext));
|
||||
textView.setEnabled(mWrapperList.get(position).isEnabled());
|
||||
textView.setChecked(mWrapperList.get(position).isChecked());
|
||||
textView.setOnClickListener(l -> {
|
||||
textView.toggle();
|
||||
mWrapperList.get(position).setChecked(textView.isChecked());
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.verify.domain.DomainVerificationManager;
|
||||
import android.content.pm.verify.domain.DomainVerificationUserState;
|
||||
import android.os.Bundle;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/** A customized {@link DialogFragment} with multiple checkboxes. */
|
||||
public class SupportedLinksDialogFragment extends DialogFragment {
|
||||
private static final String TAG = "SupportedLinksDialogFrg";
|
||||
private static final String DLG_ID = "SupportedLinksDialog";
|
||||
|
||||
private SupportedLinkViewModel mViewModel;
|
||||
private List<SupportedLinkWrapper> mSupportedLinkWrapperList;
|
||||
private String mPackage;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mPackage = getArguments().getString(AppLaunchSettings.APP_PACKAGE_KEY);
|
||||
mViewModel = ViewModelProviders.of(this.getActivity()).get(SupportedLinkViewModel.class);
|
||||
mSupportedLinkWrapperList = mViewModel.getSupportedLinkWrapperList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
final SupportedLinksAdapter adapter = new SupportedLinksAdapter(context,
|
||||
mSupportedLinkWrapperList);
|
||||
final AlertDialog.Builder builder = new AlertDialog
|
||||
.Builder(context)
|
||||
.setTitle(IntentPickerUtils.getCentralizedDialogTitle(getSupportedLinksTitle()))
|
||||
.setAdapter(adapter, /* listener= */ null)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.app_launch_supported_links_add, (dialog, id) -> {
|
||||
// addSelectedItems(((AlertDialog) dialog).getListView());
|
||||
doSelectedAction();
|
||||
})
|
||||
.setNegativeButton(R.string.app_launch_dialog_cancel, /* listener= */ null);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
/** Display the dialog. */
|
||||
public void showDialog(FragmentManager manager) {
|
||||
show(manager, DLG_ID);
|
||||
}
|
||||
|
||||
private String getSupportedLinksTitle() {
|
||||
final int supportedLinksNo = mSupportedLinkWrapperList.size();
|
||||
return getResources().getQuantityString(
|
||||
R.plurals.app_launch_supported_links_title, supportedLinksNo, supportedLinksNo);
|
||||
}
|
||||
|
||||
private void doSelectedAction() {
|
||||
final DomainVerificationManager manager = getActivity().getSystemService(
|
||||
DomainVerificationManager.class);
|
||||
final DomainVerificationUserState userState =
|
||||
IntentPickerUtils.getDomainVerificationUserState(manager, mPackage);
|
||||
if (userState == null || mSupportedLinkWrapperList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateUserSelection(manager, userState);
|
||||
displaySelectedItem();
|
||||
}
|
||||
|
||||
private void updateUserSelection(DomainVerificationManager manager,
|
||||
DomainVerificationUserState userState) {
|
||||
final Set<String> domainSet = new ArraySet<>();
|
||||
for (SupportedLinkWrapper wrapper : mSupportedLinkWrapperList) {
|
||||
if (wrapper.isChecked()) {
|
||||
domainSet.add(wrapper.getHost());
|
||||
}
|
||||
}
|
||||
if (domainSet.size() > 0) {
|
||||
setDomainVerificationUserSelection(manager, userState.getIdentifier(),
|
||||
domainSet, /* enabled= */true);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDomainVerificationUserSelection(DomainVerificationManager manager,
|
||||
UUID identifier, Set<String> domainSet, boolean isEnabled) {
|
||||
try {
|
||||
manager.setDomainVerificationUserSelection(identifier, domainSet, isEnabled);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "addSelectedItems : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void displaySelectedItem() {
|
||||
final List<Fragment> fragments = getActivity().getSupportFragmentManager().getFragments();
|
||||
for (Fragment fragment : fragments) {
|
||||
if (fragment instanceof AppLaunchSettings) {
|
||||
((AppLaunchSettings) fragment).addSelectedLinksPreference();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.widget.TwoTargetPreference;
|
||||
|
||||
/** This customized VerifiedLinksPreference was belonged to Open by default page */
|
||||
public class VerifiedLinksPreference extends TwoTargetPreference {
|
||||
private Context mContext;
|
||||
private View.OnClickListener mOnWidgetClickListener;
|
||||
private boolean mShowCheckBox;
|
||||
|
||||
public VerifiedLinksPreference(Context context, AttributeSet attrs,
|
||||
int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public VerifiedLinksPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, /* defStyleRes= */0);
|
||||
}
|
||||
|
||||
public VerifiedLinksPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, /* defStyleAttr= */ 0);
|
||||
}
|
||||
|
||||
public VerifiedLinksPreference(Context context) {
|
||||
this(context, /* attrs= */ null);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mContext = context;
|
||||
mOnWidgetClickListener = null;
|
||||
mShowCheckBox = true;
|
||||
setLayoutResource(R.layout.preference_checkable_two_target);
|
||||
setWidgetLayoutResource(R.layout.verified_links_widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when this widget is clicked.
|
||||
*
|
||||
* @param listener The callback that will run.
|
||||
*/
|
||||
public void setWidgetFrameClickListener(View.OnClickListener listener) {
|
||||
mOnWidgetClickListener = listener;
|
||||
}
|
||||
|
||||
/** Determine the visibility of the {@link CheckBox}. */
|
||||
public void setCheckBoxVisible(boolean isVisible) {
|
||||
mShowCheckBox = isVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder view) {
|
||||
super.onBindViewHolder(view);
|
||||
final View settingsWidget = view.findViewById(android.R.id.widget_frame);
|
||||
final View divider = view.findViewById(R.id.two_target_divider);
|
||||
divider.setVisibility(View.VISIBLE);
|
||||
settingsWidget.setVisibility(View.VISIBLE);
|
||||
if (mOnWidgetClickListener != null) {
|
||||
settingsWidget.setOnClickListener(mOnWidgetClickListener);
|
||||
}
|
||||
final View checkboxContainer = view.findViewById(R.id.checkbox_container);
|
||||
final View parentView = (View) checkboxContainer.getParent();
|
||||
parentView.setEnabled(false);
|
||||
parentView.setClickable(false);
|
||||
CheckBox checkBox = (CheckBox) view.findViewById(com.android.internal.R.id.checkbox);
|
||||
if (checkBox != null) {
|
||||
checkBox.setChecked(true);
|
||||
checkBox.setVisibility(mShowCheckBox ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@@ -28,7 +28,7 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.AppInfoBase;
|
||||
import com.android.settings.applications.AppLaunchSettings;
|
||||
import com.android.settings.applications.intentpicker.AppLaunchSettings;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
|
@@ -37,7 +37,7 @@ import android.content.pm.ResolveInfo;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.applications.AppLaunchSettings;
|
||||
import com.android.settings.applications.intentpicker.AppLaunchSettings;
|
||||
import com.android.settingslib.applications.AppUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
|
||||
|
Reference in New Issue
Block a user