Merge sc-v2-dev-plus-aosp-without-vendor@8084891
Bug: 214455710 Merged-In: I962c318f41adcf180b885f2052ce0ec4952edfb6 Change-Id: I77764eaf895ac3c13c7440adb5b3f597a516d690
This commit is contained in:
@@ -83,13 +83,14 @@ public class Settings extends SettingsActivity {
|
||||
}
|
||||
|
||||
public static class VpnSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class DataSaverSummaryActivity extends SettingsActivity{ /* empty */ }
|
||||
/** Activity for Data saver settings. */
|
||||
public static class DataSaverSummaryActivity extends SettingsActivity { /* empty */ }
|
||||
public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PrivateVolumeForgetActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PublicVolumeSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class WifiSettings2Activity extends SettingsActivity { /* empty */ }
|
||||
public static class NetworkProviderSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NetworkSelectActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity for the Wi-Fi network details settings. */
|
||||
public static class WifiDetailsSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
@@ -121,13 +122,11 @@ public class Settings extends SettingsActivity {
|
||||
public static class AccessibilityInversionSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AccessibilityContrastSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AccessibilityDaltonizerSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/**
|
||||
* Activity for lockscreen settings.
|
||||
*/
|
||||
/** Activity for lockscreen settings. */
|
||||
public static class LockScreenSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/**
|
||||
* Activity for Reduce Bright Colors.
|
||||
*/
|
||||
/** Activity for bluetooth pairing settings. */
|
||||
public static class BlueToothPairingActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity for Reduce Bright Colors. */
|
||||
public static class ReduceBrightColorsSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity for the security dashboard. */
|
||||
public static class SecurityDashboardActivity extends SettingsActivity {
|
||||
|
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import static android.provider.Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY;
|
||||
import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY;
|
||||
import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI;
|
||||
|
||||
import static com.android.settings.applications.appinfo.AppButtonsPreferenceController.KEY_REMOVE_TASK_WHEN_FINISHING;
|
||||
|
||||
import android.app.ActionBar;
|
||||
@@ -29,6 +33,7 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.AsyncTask;
|
||||
@@ -52,12 +57,15 @@ import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.settings.Settings.WifiSettingsActivity;
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
|
||||
import com.android.settings.applications.manageapplications.ManageApplications;
|
||||
import com.android.settings.core.OnActivityResultListener;
|
||||
import com.android.settings.core.SettingsBaseActivity;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.core.gateway.SettingsGateway;
|
||||
import com.android.settings.dashboard.DashboardFeatureProvider;
|
||||
import com.android.settings.homepage.SettingsHomepageActivity;
|
||||
import com.android.settings.homepage.SliceDeepLinkHomepageActivity;
|
||||
import com.android.settings.homepage.TopLevelSettings;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.wfd.WifiDisplaySettings;
|
||||
@@ -136,6 +144,12 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
public static final String EXTRA_SHOW_FRAGMENT_AS_SUBSETTING =
|
||||
":settings:show_fragment_as_subsetting";
|
||||
|
||||
/**
|
||||
* Additional extra of Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK.
|
||||
* Set true when the deep link intent is from a slice
|
||||
*/
|
||||
public static final String EXTRA_IS_FROM_SLICE = "is_from_slice";
|
||||
|
||||
/**
|
||||
* Personal or Work profile tab of {@link ProfileSelectFragment}
|
||||
* <p>0: Personal tab.
|
||||
@@ -147,9 +161,13 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
public static final String META_DATA_KEY_FRAGMENT_CLASS =
|
||||
"com.android.settings.FRAGMENT_CLASS";
|
||||
|
||||
public static final String META_DATA_KEY_HIGHLIGHT_MENU_KEY =
|
||||
"com.android.settings.HIGHLIGHT_MENU_KEY";
|
||||
|
||||
private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
|
||||
|
||||
private String mFragmentClass;
|
||||
private String mHighlightMenuKey;
|
||||
|
||||
private CharSequence mInitialTitle;
|
||||
private int mInitialTitleResId;
|
||||
@@ -229,18 +247,25 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedState) {
|
||||
// Should happen before any call to getIntent()
|
||||
getMetaData();
|
||||
final Intent intent = getIntent();
|
||||
|
||||
if (shouldShowTwoPaneDeepLink(intent)) {
|
||||
launchHomepageForTwoPaneDeepLink(intent);
|
||||
finishAndRemoveTask();
|
||||
super.onCreate(savedState);
|
||||
return;
|
||||
}
|
||||
|
||||
super.onCreate(savedState);
|
||||
Log.d(LOG_TAG, "Starting onCreate");
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
final FeatureFactory factory = FeatureFactory.getFactory(this);
|
||||
|
||||
mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this);
|
||||
|
||||
// Should happen before any call to getIntent()
|
||||
getMetaData();
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent.hasExtra(EXTRA_UI_OPTIONS)) {
|
||||
getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
|
||||
}
|
||||
@@ -248,17 +273,11 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
// Getting Intent properties can only be done after the super.onCreate(...)
|
||||
final String initialFragmentName = getInitialFragmentName(intent);
|
||||
|
||||
// This is a "Sub Settings" when:
|
||||
// - this is a real SubSettings
|
||||
// - or :settings:show_fragment_as_subsetting is passed to the Intent
|
||||
final boolean isSubSettings = this instanceof SubSettings ||
|
||||
intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
|
||||
|
||||
// If this is a sub settings, then apply the SubSettings Theme for the ActionBar content
|
||||
// insets.
|
||||
// If this is in setup flow, don't apply theme. Because light theme needs to be applied
|
||||
// in SettingsBaseActivity#onCreate().
|
||||
if (isSubSettings && !WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
if (isSubSettings(intent) && !WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
setTheme(R.style.Theme_SubSettings);
|
||||
}
|
||||
|
||||
@@ -347,6 +366,99 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSubSettings(Intent intent) {
|
||||
return this instanceof SubSettings ||
|
||||
intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the deep link trampoline intent for large screen devices.
|
||||
*/
|
||||
public static Intent getTrampolineIntent(Intent intent, String highlightMenuKey) {
|
||||
final Intent detailIntent = new Intent(intent);
|
||||
// It's a deep link intent, SettingsHomepageActivity will set SplitPairRule and start it.
|
||||
final Intent trampolineIntent = new Intent(ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY)
|
||||
.setPackage(Utils.SETTINGS_PACKAGE_NAME)
|
||||
.replaceExtras(detailIntent);
|
||||
|
||||
// Relay detail intent data to prevent failure of Intent#ParseUri.
|
||||
// If Intent#getData() is not null, Intent#toUri will return an Uri which has the scheme of
|
||||
// Intent#getData() and it may not be the scheme of an Intent.
|
||||
trampolineIntent.putExtra(
|
||||
SettingsHomepageActivity.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA,
|
||||
detailIntent.getData());
|
||||
detailIntent.setData(null);
|
||||
|
||||
trampolineIntent.putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
|
||||
detailIntent.toUri(Intent.URI_INTENT_SCHEME));
|
||||
|
||||
trampolineIntent.putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY,
|
||||
highlightMenuKey);
|
||||
trampolineIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
return trampolineIntent;
|
||||
}
|
||||
|
||||
private void launchHomepageForTwoPaneDeepLink(Intent intent) {
|
||||
final Intent trampolineIntent;
|
||||
if (intent.getBooleanExtra(EXTRA_IS_FROM_SLICE, false)) {
|
||||
// Get menu key for slice deep link case.
|
||||
final String highlightMenuKey = intent.getStringExtra(
|
||||
EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY);
|
||||
if (!TextUtils.isEmpty(highlightMenuKey)) {
|
||||
mHighlightMenuKey = highlightMenuKey;
|
||||
}
|
||||
trampolineIntent = getTrampolineIntent(intent, mHighlightMenuKey);
|
||||
trampolineIntent.setClass(this, SliceDeepLinkHomepageActivity.class);
|
||||
} else {
|
||||
trampolineIntent = getTrampolineIntent(intent, mHighlightMenuKey);
|
||||
}
|
||||
startActivity(trampolineIntent);
|
||||
}
|
||||
|
||||
private boolean shouldShowTwoPaneDeepLink(Intent intent) {
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the activity is not the task root, it should not start trampoline for deep links.
|
||||
if (!isTaskRoot()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only starts trampoline for deep links. Should return false for all the cases that
|
||||
// Settings app starts SettingsActivity or SubSetting by itself.
|
||||
if (intent.getAction() == null) {
|
||||
// Other apps should send deep link intent which matches intent filter of the Activity.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_IS_FROM_SLICE, false)) {
|
||||
// Slice deep link starts the Intent using SubSettingLauncher. Returns true to show
|
||||
// 2-pane deep link.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isSubSettings(intent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intent.getBooleanExtra(SettingsHomepageActivity.EXTRA_IS_FROM_SETTINGS_HOMEPAGE,
|
||||
/* defaultValue */ false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.equals(intent.getAction(), Intent.ACTION_CREATE_SHORTCUT)) {
|
||||
// Returns false to show full screen for Intent.ACTION_CREATE_SHORTCUT because
|
||||
// - Launcher startActivityForResult for Intent.ACTION_CREATE_SHORTCUT and activity
|
||||
// stack starts from launcher, CreateShortcutActivity will not follows SplitPaitRule
|
||||
// registered by Settings.
|
||||
// - There is no CreateShortcutActivity entry point from Settings app UI.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the initial fragment name that the activity will launch. */
|
||||
@VisibleForTesting
|
||||
public String getInitialFragmentName(Intent intent) {
|
||||
@@ -407,6 +519,9 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
return;
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(LOG_TAG, "Could not find package" + initialTitleResPackageName);
|
||||
} catch (Resources.NotFoundException resourceNotFound) {
|
||||
Log.w(LOG_TAG,
|
||||
"Could not find title resource in " + initialTitleResPackageName);
|
||||
}
|
||||
} else {
|
||||
setTitle(mInitialTitleResId);
|
||||
@@ -716,6 +831,7 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
PackageManager.GET_META_DATA);
|
||||
if (ai == null || ai.metaData == null) return;
|
||||
mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
|
||||
mHighlightMenuKey = ai.metaData.getString(META_DATA_KEY_HIGHLIGHT_MENU_KEY);
|
||||
} catch (NameNotFoundException nnfe) {
|
||||
// No recovery
|
||||
Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());
|
||||
|
47
src/com/android/settings/SettingsApplication.java
Normal file
47
src/com/android/settings/SettingsApplication.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
|
||||
import com.android.settings.homepage.SettingsHomepageActivity;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/** Settings application which sets up activity embedding rules for the large screen device. */
|
||||
public class SettingsApplication extends Application {
|
||||
|
||||
private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null);
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
final ActivityEmbeddingRulesController controller =
|
||||
new ActivityEmbeddingRulesController(this);
|
||||
controller.initRules();
|
||||
}
|
||||
|
||||
public void setHomeActivity(SettingsHomepageActivity homeActivity) {
|
||||
mHomeActivity = new WeakReference<>(homeActivity);
|
||||
}
|
||||
|
||||
public SettingsHomepageActivity getHomeActivity() {
|
||||
return mHomeActivity.get();
|
||||
}
|
||||
}
|
@@ -37,8 +37,11 @@ import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.window.embedding.SplitController;
|
||||
|
||||
import com.android.settings.Settings.CreateShortcutActivity;
|
||||
import com.android.settings.homepage.DeepLinkHomepageActivity;
|
||||
import com.android.settings.search.SearchStateReceiver;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -48,7 +51,8 @@ import java.util.List;
|
||||
* Listens to {@link Intent.ACTION_PRE_BOOT_COMPLETED} and {@link Intent.ACTION_USER_INITIALIZED}
|
||||
* performs setup steps for a managed profile (disables the launcher icon of the Settings app,
|
||||
* adds cross-profile intent filters for the appropriate Settings activities), disables the
|
||||
* webview setting for non-admin users, and updates the intent flags for any existing shortcuts.
|
||||
* webview setting for non-admin users, updates the intent flags for any existing shortcuts and
|
||||
* enables DeepLinkHomepageActivity for large screen devices.
|
||||
*/
|
||||
public class SettingsInitialize extends BroadcastReceiver {
|
||||
private static final String TAG = "Settings";
|
||||
@@ -64,6 +68,7 @@ public class SettingsInitialize extends BroadcastReceiver {
|
||||
managedProfileSetup(context, pm, broadcast, userInfo);
|
||||
webviewSettingSetup(context, pm, userInfo);
|
||||
ThreadUtils.postOnBackgroundThread(() -> refreshExistingShortcuts(context));
|
||||
enableTwoPaneDeepLinkActivityIfNecessary(pm, context);
|
||||
}
|
||||
|
||||
private void managedProfileSetup(Context context, final PackageManager pm, Intent broadcast,
|
||||
@@ -143,4 +148,17 @@ public class SettingsInitialize extends BroadcastReceiver {
|
||||
}
|
||||
shortcutManager.updateShortcuts(updates);
|
||||
}
|
||||
|
||||
private void enableTwoPaneDeepLinkActivityIfNecessary(PackageManager pm, Context context) {
|
||||
final ComponentName deepLinkHome = new ComponentName(context,
|
||||
DeepLinkHomepageActivity.class);
|
||||
final ComponentName searchStateReceiver = new ComponentName(context,
|
||||
SearchStateReceiver.class);
|
||||
final int enableState = SplitController.getInstance().isSplitSupported()
|
||||
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||
pm.setComponentEnabledSetting(deepLinkHome, enableState, PackageManager.DONT_KILL_APP);
|
||||
pm.setComponentEnabledSetting(searchStateReceiver, enableState,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
}
|
||||
|
@@ -119,8 +119,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
|
||||
|
||||
@VisibleForTesting
|
||||
public HighlightablePreferenceGroupAdapter mAdapter;
|
||||
@VisibleForTesting
|
||||
public boolean mPreferenceHighlighted = false;
|
||||
private boolean mPreferenceHighlighted = false;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
|
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilityGestureNavigationTutorial;
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* This activity is to create the tutorial dialog in gesture navigation settings since we couldn't
|
||||
* use the dialog utils because SystemNavigationGestureSettings extends RadioButtonPickerFragment,
|
||||
* not SettingsPreferenceFragment.
|
||||
*/
|
||||
public class SettingsTutorialDialogWrapperActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
showDialog();
|
||||
}
|
||||
|
||||
private void showDialog() {
|
||||
AccessibilityGestureNavigationTutorial
|
||||
.showGestureNavigationSettingsTutorialDialog(this, dialog -> finish());
|
||||
}
|
||||
}
|
@@ -1013,7 +1013,8 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
Drawable safeIcon = icon;
|
||||
|
||||
if ((icon != null) && !(icon instanceof VectorDrawable)) {
|
||||
safeIcon = getSafeDrawable(icon, 500, 500);
|
||||
safeIcon = getSafeDrawable(icon,
|
||||
/* MAX_DRAWABLE_SIZE */ 600, /* MAX_DRAWABLE_SIZE */ 600);
|
||||
}
|
||||
|
||||
return safeIcon;
|
||||
@@ -1222,7 +1223,11 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
return getColorAttrDefaultColor(context, android.R.attr.textColorSecondary);
|
||||
}
|
||||
|
||||
public static boolean isProviderModelEnabled(Context context) {
|
||||
return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
|
||||
/**
|
||||
* Returns the highlight color of homepage preference icons.
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getHomepageIconColorHighlight(Context context) {
|
||||
return getColorAttrDefaultColor(context, android.R.attr.textColorSecondaryInverse);
|
||||
}
|
||||
}
|
||||
|
@@ -33,21 +33,26 @@ public class AccessibilityButtonFooterPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLabelName() {
|
||||
return mContext.getString(R.string.accessibility_button_title);
|
||||
protected String getLearnMoreContentDescription() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_button_gesture_footer_learn_more_content_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIntroductionTitle() {
|
||||
return mContext.getString(R.string.accessibility_button_about_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
// Need to update footerPreference's data before super.displayPreference(), then it will use
|
||||
// data to update related property of footerPreference.
|
||||
if (AccessibilityUtil.isGestureNavigateEnabled(mContext)) {
|
||||
final AccessibilityFooterPreference footerPreference =
|
||||
screen.findPreference(getPreferenceKey());
|
||||
footerPreference.setTitle(
|
||||
mContext.getString(R.string.accessibility_button_gesture_description));
|
||||
}
|
||||
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_description
|
||||
: R.string.accessibility_button_description;
|
||||
final AccessibilityFooterPreference footerPreference =
|
||||
screen.findPreference(getPreferenceKey());
|
||||
footerPreference.setTitle(titleResource);
|
||||
super.displayPreference(screen);
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
@@ -29,6 +30,14 @@ public class AccessibilityButtonFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "AccessibilityButtonFragment";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(getPrefContext())
|
||||
? R.string.accessibility_button_gesture_title : R.string.accessibility_button_title;
|
||||
getActivity().setTitle(titleResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accessibility_button_settings;
|
||||
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/** Preference controller that controls the button or gesture in accessibility button page. */
|
||||
public class AccessibilityButtonGesturePreferenceController extends BasePreferenceController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private Optional<Integer> mDefaultGesture = Optional.empty();
|
||||
|
||||
public AccessibilityButtonGesturePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final ListPreference listPreference = (ListPreference) preference;
|
||||
final Integer value = Ints.tryParse((String) newValue);
|
||||
if (value != null) {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, value);
|
||||
updateState(listPreference);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
final ListPreference listPreference = (ListPreference) preference;
|
||||
|
||||
listPreference.setValue(getCurrentAccessibilityButtonMode());
|
||||
}
|
||||
|
||||
private String getCurrentAccessibilityButtonMode() {
|
||||
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, getDefaultGestureValue());
|
||||
return String.valueOf(mode);
|
||||
}
|
||||
|
||||
private int getDefaultGestureValue() {
|
||||
if (!mDefaultGesture.isPresent()) {
|
||||
final String[] valuesList = mContext.getResources().getStringArray(
|
||||
R.array.accessibility_button_gesture_selector_values);
|
||||
mDefaultGesture = Optional.of(Integer.parseInt(valuesList[0]));
|
||||
}
|
||||
return mDefaultGesture.get();
|
||||
}
|
||||
}
|
@@ -18,7 +18,6 @@ package com.android.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
@@ -28,16 +27,16 @@ import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/** Preference controller that controls the preferred location in accessibility button page. */
|
||||
public class AccessibilityButtonLocationPreferenceController extends BasePreferenceController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private final ArrayMap<String, String> mValueTitleMap = new ArrayMap<>();
|
||||
private int mDefaultLocation;
|
||||
private Optional<Integer> mDefaultLocation = Optional.empty();
|
||||
|
||||
public AccessibilityButtonLocationPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
initValueTitleMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,22 +67,16 @@ public class AccessibilityButtonLocationPreferenceController extends BasePrefere
|
||||
|
||||
private String getCurrentAccessibilityButtonMode() {
|
||||
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mDefaultLocation);
|
||||
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, getDefaultLocationValue());
|
||||
return String.valueOf(mode);
|
||||
}
|
||||
|
||||
private void initValueTitleMap() {
|
||||
if (mValueTitleMap.size() == 0) {
|
||||
final String[] values = mContext.getResources().getStringArray(
|
||||
private int getDefaultLocationValue() {
|
||||
if (!mDefaultLocation.isPresent()) {
|
||||
final String[] valuesList = mContext.getResources().getStringArray(
|
||||
R.array.accessibility_button_location_selector_values);
|
||||
final String[] titles = mContext.getResources().getStringArray(
|
||||
R.array.accessibility_button_location_selector_titles);
|
||||
final int mapSize = values.length;
|
||||
|
||||
mDefaultLocation = Integer.parseInt(values[0]);
|
||||
for (int i = 0; i < mapSize; i++) {
|
||||
mValueTitleMap.put(values[i], titles[i]);
|
||||
}
|
||||
mDefaultLocation = Optional.of(Integer.parseInt(valuesList[0]));
|
||||
}
|
||||
return mDefaultLocation.get();
|
||||
}
|
||||
}
|
||||
|
@@ -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.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/**
|
||||
* Preference controller for accessibility button preference.
|
||||
*/
|
||||
public class AccessibilityButtonPreferenceController extends BasePreferenceController {
|
||||
|
||||
public AccessibilityButtonPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_title : R.string.accessibility_button_title;
|
||||
final Preference preference = screen.findPreference(getPreferenceKey());
|
||||
preference.setTitle(titleResource);
|
||||
|
||||
}
|
||||
}
|
@@ -23,7 +23,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.widget.ImageView;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
@@ -33,7 +33,7 @@ import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
import com.android.settingslib.widget.IllustrationPreference;
|
||||
|
||||
/** Preference controller that controls the preview effect in accessibility button page. */
|
||||
public class AccessibilityButtonPreviewPreferenceController extends BasePreferenceController
|
||||
@@ -46,10 +46,12 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
private final ContentResolver mContentResolver;
|
||||
@VisibleForTesting
|
||||
final ContentObserver mContentObserver;
|
||||
private FloatingMenuLayerDrawable mFloatingMenuPreviewDrawable;
|
||||
|
||||
private AccessibilityLayerDrawable mAccessibilityPreviewDrawable;
|
||||
@VisibleForTesting
|
||||
ImageView mPreview;
|
||||
IllustrationPreference mIllustrationPreference;
|
||||
|
||||
private AccessibilityManager.TouchExplorationStateChangeListener
|
||||
mTouchExplorationStateChangeListener;
|
||||
|
||||
public AccessibilityButtonPreviewPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
@@ -60,6 +62,9 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
updatePreviewPreference();
|
||||
}
|
||||
};
|
||||
mTouchExplorationStateChangeListener = isTouchExplorationEnabled -> {
|
||||
updatePreviewPreference();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,14 +75,16 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
final LayoutPreference preference = screen.findPreference(getPreferenceKey());
|
||||
mPreview = preference.findViewById(R.id.preview_image);
|
||||
mIllustrationPreference = screen.findPreference(getPreferenceKey());
|
||||
|
||||
updatePreviewPreference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
final AccessibilityManager am = mContext.getSystemService(AccessibilityManager.class);
|
||||
am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
|
||||
|
||||
mContentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE),
|
||||
/* notifyForDescendants= */ false, mContentObserver);
|
||||
@@ -91,6 +98,9 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
final AccessibilityManager am = mContext.getSystemService(AccessibilityManager.class);
|
||||
am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
|
||||
|
||||
mContentResolver.unregisterContentObserver(mContentObserver);
|
||||
}
|
||||
|
||||
@@ -103,24 +113,29 @@ public class AccessibilityButtonPreviewPreferenceController extends BasePreferen
|
||||
final int floatingMenuIconId = (size == SMALL_SIZE)
|
||||
? R.drawable.accessibility_button_preview_small_floating_menu
|
||||
: R.drawable.accessibility_button_preview_large_floating_menu;
|
||||
|
||||
mPreview.setImageDrawable(getFloatingMenuPreviewDrawable(floatingMenuIconId, opacity));
|
||||
// Only change opacity(alpha) would not invoke redraw view, need to invalidate manually.
|
||||
mPreview.invalidate();
|
||||
mIllustrationPreference.setImageDrawable(
|
||||
getAccessibilityPreviewDrawable(floatingMenuIconId, opacity));
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(mContext)) {
|
||||
mIllustrationPreference.setImageDrawable(mContext.getDrawable(
|
||||
AccessibilityUtil.isTouchExploreEnabled(mContext)
|
||||
? R.drawable.accessibility_button_preview_three_finger
|
||||
: R.drawable.accessibility_button_preview_two_finger));
|
||||
} else {
|
||||
mPreview.setImageDrawable(
|
||||
mIllustrationPreference.setImageDrawable(
|
||||
mContext.getDrawable(R.drawable.accessibility_button_navigation));
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getFloatingMenuPreviewDrawable(int resId, int opacity) {
|
||||
if (mFloatingMenuPreviewDrawable == null) {
|
||||
mFloatingMenuPreviewDrawable = FloatingMenuLayerDrawable.createLayerDrawable(
|
||||
private Drawable getAccessibilityPreviewDrawable(int resId, int opacity) {
|
||||
if (mAccessibilityPreviewDrawable == null) {
|
||||
mAccessibilityPreviewDrawable = AccessibilityLayerDrawable.createLayerDrawable(
|
||||
mContext, resId, opacity);
|
||||
} else {
|
||||
mFloatingMenuPreviewDrawable.updateLayerDrawable(mContext, resId, opacity);
|
||||
mAccessibilityPreviewDrawable.updateLayerDrawable(mContext, resId, opacity);
|
||||
// Only change alpha (opacity) value did not change drawable id. It needs to force to
|
||||
// redraw.
|
||||
mAccessibilityPreviewDrawable.invalidateSelf();
|
||||
}
|
||||
|
||||
return mFloatingMenuPreviewDrawable;
|
||||
return mAccessibilityPreviewDrawable;
|
||||
}
|
||||
}
|
||||
|
@@ -31,8 +31,14 @@ public class AccessibilityControlTimeoutFooterPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLabelName() {
|
||||
return mContext.getString(R.string.accessibility_setting_item_control_timeout_title);
|
||||
protected String getLearnMoreContentDescription() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_control_timeout_footer_learn_more_content_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIntroductionTitle() {
|
||||
return mContext.getString(R.string.accessibility_control_timeout_about_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -69,7 +69,7 @@ public final class AccessibilityControlTimeoutPreferenceFragment extends Dashboa
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCESSIBILITY;
|
||||
return SettingsEnums.ACCESSIBILITY_TIMEOUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -31,6 +31,7 @@ import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.AbsListView;
|
||||
@@ -44,9 +45,11 @@ import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RawRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
@@ -54,6 +57,9 @@ import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.utils.AnnotationSpan;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.airbnb.lottie.LottieDrawable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
@@ -63,6 +69,7 @@ import java.util.List;
|
||||
* Utility class for creating the edit dialog.
|
||||
*/
|
||||
public class AccessibilityDialogUtils {
|
||||
private static final String TAG = "AccessibilityDialogUtils";
|
||||
|
||||
/** Denotes the dialog emuns for show dialog. */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -173,6 +180,23 @@ public class AccessibilityDialogUtils {
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the software shortcut in edit shortcut dialog.
|
||||
*
|
||||
* @param context A valid context
|
||||
* @param editShortcutDialog Need to be a type of edit shortcut dialog
|
||||
* @return True if the update is successful
|
||||
*/
|
||||
public static boolean updateSoftwareShortcutInDialog(Context context,
|
||||
Dialog editShortcutDialog) {
|
||||
final View container = editShortcutDialog.findViewById(R.id.container_layout);
|
||||
if (container != null) {
|
||||
initSoftwareShortcut(context, container);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static AlertDialog createDialog(Context context, int dialogType,
|
||||
CharSequence dialogTitle, DialogInterface.OnClickListener listener) {
|
||||
|
||||
@@ -315,9 +339,22 @@ public class AccessibilityDialogUtils {
|
||||
}
|
||||
|
||||
private static void setupShortcutWidget(View view, CharSequence titleText,
|
||||
CharSequence summaryText, int imageResId) {
|
||||
CharSequence summaryText, @DrawableRes int imageResId) {
|
||||
setupShortcutWidgetWithTitleAndSummary(view, titleText, summaryText);
|
||||
setupShortcutWidgetWithImageResource(view, imageResId);
|
||||
}
|
||||
|
||||
private static void setupShortcutWidgetWithImageRawResource(View view, CharSequence titleText,
|
||||
CharSequence summaryText, @RawRes int imageRawResId) {
|
||||
setupShortcutWidgetWithTitleAndSummary(view, titleText, summaryText);
|
||||
setupShortcutWidgetWithImageRawResource(view, imageRawResId);
|
||||
}
|
||||
|
||||
private static void setupShortcutWidgetWithTitleAndSummary(View view, CharSequence titleText,
|
||||
CharSequence summaryText) {
|
||||
final CheckBox checkBox = view.findViewById(R.id.checkbox);
|
||||
checkBox.setText(titleText);
|
||||
|
||||
final TextView summary = view.findViewById(R.id.summary);
|
||||
if (TextUtils.isEmpty(summaryText)) {
|
||||
summary.setVisibility(View.GONE);
|
||||
@@ -326,8 +363,23 @@ public class AccessibilityDialogUtils {
|
||||
summary.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
summary.setFocusable(false);
|
||||
}
|
||||
final ImageView image = view.findViewById(R.id.image);
|
||||
image.setImageResource(imageResId);
|
||||
}
|
||||
|
||||
private static void setupShortcutWidgetWithImageResource(View view,
|
||||
@DrawableRes int imageResId) {
|
||||
final ImageView imageView = view.findViewById(R.id.image);
|
||||
imageView.setImageResource(imageResId);
|
||||
}
|
||||
|
||||
private static void setupShortcutWidgetWithImageRawResource(View view,
|
||||
@RawRes int imageRawResId) {
|
||||
final LottieAnimationView lottieView = view.findViewById(R.id.image);
|
||||
lottieView.setFailureListener(
|
||||
result -> Log.w(TAG, "Invalid image raw resource id: " + imageRawResId,
|
||||
result));
|
||||
lottieView.setAnimation(imageRawResId);
|
||||
lottieView.setRepeatCount(LottieDrawable.INFINITE);
|
||||
lottieView.playAnimation();
|
||||
}
|
||||
|
||||
private static void initSoftwareShortcutForSUW(Context context, View view) {
|
||||
@@ -344,12 +396,11 @@ public class AccessibilityDialogUtils {
|
||||
|
||||
private static void initSoftwareShortcut(Context context, View view) {
|
||||
final View dialogView = view.findViewById(R.id.software_shortcut);
|
||||
final CharSequence title = context.getText(
|
||||
R.string.accessibility_shortcut_edit_dialog_title_software);
|
||||
final TextView summary = dialogView.findViewById(R.id.summary);
|
||||
final int lineHeight = summary.getLineHeight();
|
||||
|
||||
setupShortcutWidget(dialogView, title,
|
||||
setupShortcutWidget(dialogView,
|
||||
retrieveTitle(context),
|
||||
retrieveSoftwareShortcutSummary(context, lineHeight),
|
||||
retrieveSoftwareShortcutImageResId(context));
|
||||
}
|
||||
@@ -362,7 +413,6 @@ public class AccessibilityDialogUtils {
|
||||
R.string.accessibility_shortcut_edit_dialog_summary_hardware);
|
||||
setupShortcutWidget(dialogView, title, summary,
|
||||
R.drawable.accessibility_shortcut_type_hardware);
|
||||
// TODO(b/142531156): Use vector drawable instead of temporal png file to avoid distorted.
|
||||
}
|
||||
|
||||
private static void initMagnifyShortcut(Context context, View view) {
|
||||
@@ -375,9 +425,8 @@ public class AccessibilityDialogUtils {
|
||||
final Object[] arguments = {3};
|
||||
summary = MessageFormat.format(summary, arguments);
|
||||
|
||||
setupShortcutWidget(dialogView, title, summary,
|
||||
R.drawable.accessibility_shortcut_type_triple_tap);
|
||||
// TODO(b/142531156): Use vector drawable instead of temporal png file to avoid distorted.
|
||||
setupShortcutWidgetWithImageRawResource(dialogView, title, summary,
|
||||
R.raw.accessibility_shortcut_type_triple_tap);
|
||||
}
|
||||
|
||||
private static void initAdvancedWidget(View view) {
|
||||
@@ -398,20 +447,49 @@ public class AccessibilityDialogUtils {
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static CharSequence retrieveTitle(Context context) {
|
||||
int resId;
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
resId = R.string.accessibility_shortcut_edit_dialog_title_software;
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
resId = R.string.accessibility_shortcut_edit_dialog_title_software_by_gesture;
|
||||
} else {
|
||||
resId = R.string.accessibility_shortcut_edit_dialog_title_software;
|
||||
}
|
||||
return context.getText(resId);
|
||||
}
|
||||
|
||||
private static CharSequence retrieveSoftwareShortcutSummary(Context context, int lineHeight) {
|
||||
final SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
if (!AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
sb.append(getCustomizeAccessibilityButtonLink(context));
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
final int resId = AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.string.accessibility_shortcut_edit_dialog_summary_software_gesture_talkback
|
||||
: R.string.accessibility_shortcut_edit_dialog_summary_software_gesture;
|
||||
sb.append(context.getText(resId));
|
||||
sb.append("\n\n");
|
||||
sb.append(getCustomizeAccessibilityButtonLink(context));
|
||||
} else {
|
||||
sb.append(getSummaryStringWithIcon(context, lineHeight));
|
||||
sb.append("\n\n");
|
||||
sb.append(getCustomizeAccessibilityButtonLink(context));
|
||||
}
|
||||
sb.append(getCustomizeAccessibilityButtonLink(context));
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static int retrieveSoftwareShortcutImageResId(Context context) {
|
||||
return AccessibilityUtil.isFloatingMenuEnabled(context)
|
||||
? R.drawable.accessibility_shortcut_type_software_floating
|
||||
: R.drawable.accessibility_shortcut_type_software;
|
||||
int resId;
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
resId = R.drawable.accessibility_shortcut_type_software_floating;
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
resId = AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.drawable.accessibility_shortcut_type_software_gesture_talkback
|
||||
: R.drawable.accessibility_shortcut_type_software_gesture;
|
||||
} else {
|
||||
resId = R.drawable.accessibility_shortcut_type_software;
|
||||
}
|
||||
return resId;
|
||||
}
|
||||
|
||||
private static CharSequence getCustomizeAccessibilityButtonLink(Context context) {
|
||||
@@ -422,7 +500,6 @@ public class AccessibilityDialogUtils {
|
||||
.launch();
|
||||
final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
|
||||
AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, linkListener);
|
||||
|
||||
return AnnotationSpan.linkify(context.getText(
|
||||
R.string.accessibility_shortcut_edit_dialog_summary_software_floating), linkInfo);
|
||||
}
|
||||
|
@@ -21,14 +21,18 @@ import android.content.Intent;
|
||||
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.HelpUtils;
|
||||
|
||||
/**
|
||||
* Base class for accessibility preference footer.
|
||||
* Preference controller that controls the help link and customizes the preference title in {@link
|
||||
* AccessibilityFooterPreference}.
|
||||
*/
|
||||
public abstract class AccessibilityFooterPreferenceController extends BasePreferenceController {
|
||||
public class AccessibilityFooterPreferenceController extends BasePreferenceController {
|
||||
|
||||
private int mHelpResource;
|
||||
private String mLearnMoreContentDescription;
|
||||
private String mIntroductionTitle;
|
||||
|
||||
public AccessibilityFooterPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
@@ -49,36 +53,74 @@ public abstract class AccessibilityFooterPreferenceController extends BasePrefer
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this if showing a help item in the footer bar, by returning the resource id.
|
||||
* Setups a help item in the {@link AccessibilityFooterPreference} with specific content
|
||||
* description.
|
||||
*/
|
||||
public void setupHelpLink(int helpResource, String learnMoreContentDescription) {
|
||||
mHelpResource = helpResource;
|
||||
mLearnMoreContentDescription = learnMoreContentDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides this if showing a help item in the {@link AccessibilityFooterPreference}, by
|
||||
* returning the resource id.
|
||||
*
|
||||
* @return the resource id for the help url
|
||||
*/
|
||||
protected int getHelpResource() {
|
||||
return 0;
|
||||
return mHelpResource;
|
||||
}
|
||||
|
||||
/** Returns the accessibility feature name. */
|
||||
protected abstract String getLabelName();
|
||||
/**
|
||||
* Overrides this if showing a help item in the {@link AccessibilityFooterPreference} with
|
||||
* specific content description.
|
||||
*
|
||||
* @return the content description for the help url
|
||||
*/
|
||||
protected String getLearnMoreContentDescription() {
|
||||
return mLearnMoreContentDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the announcement the specific features introduction in the {@link
|
||||
* AccessibilityFooterPreference}.
|
||||
*/
|
||||
public void setIntroductionTitle(String introductionTitle) {
|
||||
mIntroductionTitle = introductionTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides this if announcement the specific features introduction in the {@link
|
||||
* AccessibilityFooterPreference}.
|
||||
*
|
||||
* @return the extended content description for specific features introduction
|
||||
*/
|
||||
protected String getIntroductionTitle() {
|
||||
return mIntroductionTitle;
|
||||
}
|
||||
|
||||
private void updateFooterPreferences(AccessibilityFooterPreference footerPreference) {
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
sb.append(mContext.getString(
|
||||
R.string.accessibility_introduction_title, getLabelName()))
|
||||
.append("\n\n")
|
||||
.append(footerPreference.getTitle());
|
||||
sb.append(getIntroductionTitle()).append("\n\n").append(footerPreference.getTitle());
|
||||
footerPreference.setContentDescription(sb);
|
||||
|
||||
final Intent helpIntent;
|
||||
if (getHelpResource() != 0) {
|
||||
// Returns may be null if content is wrong or empty.
|
||||
helpIntent = HelpUtils.getHelpIntent(mContext, mContext.getString(getHelpResource()),
|
||||
mContext.getClass().getName());
|
||||
} else {
|
||||
helpIntent = null;
|
||||
}
|
||||
|
||||
if (helpIntent != null) {
|
||||
footerPreference.setLearnMoreAction(view -> {
|
||||
final Intent helpIntent = HelpUtils.getHelpIntent(
|
||||
mContext, mContext.getString(getHelpResource()),
|
||||
mContext.getClass().getName());
|
||||
view.startActivityForResult(helpIntent, 0);
|
||||
});
|
||||
|
||||
final String learnMoreContentDescription = mContext.getString(
|
||||
R.string.footer_learn_more_content_description, getLabelName());
|
||||
footerPreference.setLearnMoreContentDescription(learnMoreContentDescription);
|
||||
footerPreference.setLearnMoreContentDescription(getLearnMoreContentDescription());
|
||||
footerPreference.setLinkEnabled(true);
|
||||
} else {
|
||||
footerPreference.setLinkEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,13 +27,15 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.TextureView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextSwitcher;
|
||||
@@ -41,8 +43,10 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.AnimRes;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RawRes;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
@@ -53,6 +57,9 @@ import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.airbnb.lottie.LottieDrawable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
@@ -63,17 +70,19 @@ import java.util.List;
|
||||
* accessibility services.
|
||||
*/
|
||||
public final class AccessibilityGestureNavigationTutorial {
|
||||
private static final String TAG = "AccessibilityGestureNavigationTutorial";
|
||||
|
||||
/** IntDef enum for dialog type. */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_BUTTON,
|
||||
DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION,
|
||||
DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE,
|
||||
DialogType.GESTURE_NAVIGATION_SETTINGS,
|
||||
})
|
||||
|
||||
private @interface DialogType {
|
||||
int LAUNCH_SERVICE_BY_ACCESSIBILITY_BUTTON = 0;
|
||||
int LAUNCH_SERVICE_BY_GESTURE_NAVIGATION = 1;
|
||||
int LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE = 1;
|
||||
int GESTURE_NAVIGATION_SETTINGS = 2;
|
||||
}
|
||||
|
||||
@@ -82,13 +91,17 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
private static final DialogInterface.OnClickListener mOnClickListener =
|
||||
(DialogInterface dialog, int which) -> dialog.dismiss();
|
||||
|
||||
public static void showGestureNavigationSettingsTutorialDialog(Context context,
|
||||
DialogInterface.OnDismissListener dismissListener) {
|
||||
/**
|
||||
* Displays a dialog that guides users to use accessibility features with accessibility
|
||||
* gestures under system gesture navigation mode.
|
||||
*/
|
||||
public static void showGestureNavigationTutorialDialog(Context context,
|
||||
DialogInterface.OnDismissListener onDismissListener) {
|
||||
final AlertDialog alertDialog = new AlertDialog.Builder(context)
|
||||
.setView(createTutorialDialogContentView(context,
|
||||
DialogType.GESTURE_NAVIGATION_SETTINGS))
|
||||
.setNegativeButton(R.string.accessibility_tutorial_dialog_button, mOnClickListener)
|
||||
.setOnDismissListener(dismissListener)
|
||||
.setOnDismissListener(onDismissListener)
|
||||
.create();
|
||||
|
||||
alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
@@ -107,8 +120,8 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
static AlertDialog showGestureNavigationTutorialDialog(Context context) {
|
||||
return createDialog(context, DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION);
|
||||
static AlertDialog showAccessibilityGestureTutorialDialog(Context context) {
|
||||
return createDialog(context, DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE);
|
||||
}
|
||||
|
||||
static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes) {
|
||||
@@ -119,7 +132,7 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a content View for a dialog to confirm that they want to enable a service.
|
||||
* Gets a content View for a dialog to confirm that they want to enable a service.
|
||||
*
|
||||
* @param context A valid context
|
||||
* @param dialogType The type of tutorial dialog
|
||||
@@ -136,42 +149,36 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
content = inflater.inflate(
|
||||
R.layout.tutorial_dialog_launch_service_by_accessibility_button, null);
|
||||
break;
|
||||
case DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION:
|
||||
case DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE:
|
||||
content = inflater.inflate(
|
||||
R.layout.tutorial_dialog_launch_service_by_gesture_navigation, null);
|
||||
final TextureView gestureTutorialVideo = content.findViewById(
|
||||
R.id.gesture_tutorial_video);
|
||||
final TextView gestureTutorialMessage = content.findViewById(
|
||||
R.id.gesture_tutorial_message);
|
||||
VideoPlayer.create(context, AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.raw.illustration_accessibility_gesture_three_finger
|
||||
: R.raw.illustration_accessibility_gesture_two_finger,
|
||||
gestureTutorialVideo);
|
||||
gestureTutorialMessage.setText(AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.string.accessibility_tutorial_dialog_message_gesture_talkback
|
||||
: R.string.accessibility_tutorial_dialog_message_gesture);
|
||||
setupGestureNavigationTextWithImage(context, content);
|
||||
break;
|
||||
case DialogType.GESTURE_NAVIGATION_SETTINGS:
|
||||
content = inflater.inflate(
|
||||
R.layout.tutorial_dialog_launch_by_gesture_navigation_settings, null);
|
||||
final TextureView gestureSettingsTutorialVideo = content.findViewById(
|
||||
R.id.gesture_tutorial_video);
|
||||
final TextView gestureSettingsTutorialMessage = content.findViewById(
|
||||
R.id.gesture_tutorial_message);
|
||||
VideoPlayer.create(context, AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.raw.illustration_accessibility_gesture_three_finger
|
||||
: R.raw.illustration_accessibility_gesture_two_finger,
|
||||
gestureSettingsTutorialVideo);
|
||||
final int stringResId = AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.string.accessibility_tutorial_dialog_message_gesture_settings_talkback
|
||||
: R.string.accessibility_tutorial_dialog_message_gesture_settings;
|
||||
gestureSettingsTutorialMessage.setText(stringResId);
|
||||
setupGestureNavigationTextWithImage(context, content);
|
||||
break;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
private static void setupGestureNavigationTextWithImage(Context context, View view) {
|
||||
final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context);
|
||||
|
||||
final ImageView imageView = view.findViewById(R.id.image);
|
||||
final int gestureSettingsImageResId =
|
||||
isTouchExploreEnabled ? R.drawable.illustration_accessibility_gesture_three_finger
|
||||
: R.drawable.illustration_accessibility_gesture_two_finger;
|
||||
imageView.setImageResource(gestureSettingsImageResId);
|
||||
|
||||
final TextView textView = view.findViewById(R.id.gesture_tutorial_message);
|
||||
textView.setText(isTouchExploreEnabled
|
||||
? R.string.accessibility_tutorial_dialog_message_gesture_settings_talkback
|
||||
: R.string.accessibility_tutorial_dialog_message_gesture_settings);
|
||||
}
|
||||
|
||||
private static AlertDialog createDialog(Context context, int dialogType) {
|
||||
final AlertDialog alertDialog = new AlertDialog.Builder(context)
|
||||
.setView(createTutorialDialogContentView(context, dialogType))
|
||||
@@ -238,7 +245,7 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
@NonNull
|
||||
@Override
|
||||
public Object instantiateItem(@NonNull ViewGroup container, int position) {
|
||||
final View itemView = mTutorialPages.get(position).getImageView();
|
||||
final View itemView = mTutorialPages.get(position).getIllustrationView();
|
||||
container.addView(itemView);
|
||||
return itemView;
|
||||
}
|
||||
@@ -256,7 +263,7 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
@Override
|
||||
public void destroyItem(@NonNull ViewGroup container, int position,
|
||||
@NonNull Object object) {
|
||||
final View itemView = mTutorialPages.get(position).getImageView();
|
||||
final View itemView = mTutorialPages.get(position).getIllustrationView();
|
||||
container.removeView(itemView);
|
||||
}
|
||||
}
|
||||
@@ -269,6 +276,34 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
return imageView;
|
||||
}
|
||||
|
||||
private static View createIllustrationView(Context context, @DrawableRes int imageRes) {
|
||||
final View illustrationFrame = inflateAndInitIllustrationFrame(context);
|
||||
final LottieAnimationView lottieView = illustrationFrame.findViewById(R.id.image);
|
||||
lottieView.setImageResource(imageRes);
|
||||
|
||||
return illustrationFrame;
|
||||
}
|
||||
|
||||
private static View createIllustrationViewWithImageRawResource(Context context,
|
||||
@RawRes int imageRawRes) {
|
||||
final View illustrationFrame = inflateAndInitIllustrationFrame(context);
|
||||
final LottieAnimationView lottieView = illustrationFrame.findViewById(R.id.image);
|
||||
lottieView.setFailureListener(
|
||||
result -> Log.w(TAG, "Invalid image raw resource id: " + imageRawRes,
|
||||
result));
|
||||
lottieView.setAnimation(imageRawRes);
|
||||
lottieView.setRepeatCount(LottieDrawable.INFINITE);
|
||||
lottieView.playAnimation();
|
||||
|
||||
return illustrationFrame;
|
||||
}
|
||||
|
||||
private static View inflateAndInitIllustrationFrame(Context context) {
|
||||
final LayoutInflater inflater = context.getSystemService(LayoutInflater.class);
|
||||
|
||||
return inflater.inflate(R.layout.accessibility_lottie_animation_view, /* root= */ null);
|
||||
}
|
||||
|
||||
private static View createShortcutNavigationContentView(Context context, int shortcutTypes) {
|
||||
final LayoutInflater inflater = context.getSystemService(LayoutInflater.class);
|
||||
final View contentView = inflater.inflate(
|
||||
@@ -323,9 +358,8 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
}
|
||||
|
||||
private static TutorialPage createSoftwareTutorialPage(@NonNull Context context) {
|
||||
final CharSequence title = context.getText(
|
||||
R.string.accessibility_tutorial_dialog_title_button);
|
||||
final ImageView image = createSoftwareImage(context);
|
||||
final CharSequence title = getSoftwareTitle(context);
|
||||
final View image = createSoftwareImage(context);
|
||||
final CharSequence instruction = getSoftwareInstruction(context);
|
||||
final ImageView indicatorIcon =
|
||||
createImageView(context, R.drawable.ic_accessibility_page_indicator);
|
||||
@@ -337,8 +371,8 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
private static TutorialPage createHardwareTutorialPage(@NonNull Context context) {
|
||||
final CharSequence title =
|
||||
context.getText(R.string.accessibility_tutorial_dialog_title_volume);
|
||||
final ImageView image =
|
||||
createImageView(context, R.drawable.accessibility_shortcut_type_hardware);
|
||||
final View image =
|
||||
createIllustrationView(context, R.drawable.accessibility_shortcut_type_hardware);
|
||||
final ImageView indicatorIcon =
|
||||
createImageView(context, R.drawable.ic_accessibility_page_indicator);
|
||||
final CharSequence instruction =
|
||||
@@ -351,8 +385,9 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
private static TutorialPage createTripleTapTutorialPage(@NonNull Context context) {
|
||||
final CharSequence title =
|
||||
context.getText(R.string.accessibility_tutorial_dialog_title_triple);
|
||||
final ImageView image =
|
||||
createImageView(context, R.drawable.accessibility_shortcut_type_triple_tap);
|
||||
final View image =
|
||||
createIllustrationViewWithImageRawResource(context,
|
||||
R.raw.accessibility_shortcut_type_triple_tap);
|
||||
final CharSequence instruction =
|
||||
context.getText(R.string.accessibility_tutorial_dialog_message_triple);
|
||||
final ImageView indicatorIcon =
|
||||
@@ -381,19 +416,47 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
return tutorialPages;
|
||||
}
|
||||
|
||||
private static ImageView createSoftwareImage(Context context) {
|
||||
final int resId = AccessibilityUtil.isFloatingMenuEnabled(context)
|
||||
? R.drawable.accessibility_shortcut_type_software_floating
|
||||
: R.drawable.accessibility_shortcut_type_software;
|
||||
private static View createSoftwareImage(Context context) {
|
||||
int resId;
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
resId = R.drawable.accessibility_shortcut_type_software_floating;
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
resId = AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.drawable.accessibility_shortcut_type_software_gesture_talkback
|
||||
: R.drawable.accessibility_shortcut_type_software_gesture;
|
||||
} else {
|
||||
resId = R.drawable.accessibility_shortcut_type_software;
|
||||
}
|
||||
return createIllustrationView(context, resId);
|
||||
}
|
||||
|
||||
return createImageView(context, resId);
|
||||
private static CharSequence getSoftwareTitle(Context context) {
|
||||
int resId;
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
resId = R.string.accessibility_tutorial_dialog_title_button;
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
resId = R.string.accessibility_tutorial_dialog_title_gesture;
|
||||
} else {
|
||||
resId = R.string.accessibility_tutorial_dialog_title_button;
|
||||
}
|
||||
return context.getText(resId);
|
||||
}
|
||||
|
||||
private static CharSequence getSoftwareInstruction(Context context) {
|
||||
return AccessibilityUtil.isFloatingMenuEnabled(context)
|
||||
? context.getText(R.string.accessibility_tutorial_dialog_message_floating_button)
|
||||
: getSoftwareInstructionWithIcon(context,
|
||||
context.getText(R.string.accessibility_tutorial_dialog_message_button));
|
||||
final SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
final int resId = R.string.accessibility_tutorial_dialog_message_floating_button;
|
||||
sb.append(context.getText(resId));
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
final int resId = AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.string.accessibility_tutorial_dialog_message_gesture_talkback
|
||||
: R.string.accessibility_tutorial_dialog_message_gesture;
|
||||
sb.append(context.getText(resId));
|
||||
} else {
|
||||
final int resId = R.string.accessibility_tutorial_dialog_message_button;
|
||||
sb.append(getSoftwareInstructionWithIcon(context, context.getText(resId)));
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) {
|
||||
@@ -416,24 +479,26 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
|
||||
private static class TutorialPage {
|
||||
private final CharSequence mTitle;
|
||||
private final ImageView mImageView;
|
||||
private final View mIllustrationView;
|
||||
private final ImageView mIndicatorIcon;
|
||||
private final CharSequence mInstruction;
|
||||
|
||||
TutorialPage(CharSequence title, ImageView imageView, ImageView indicatorIcon,
|
||||
TutorialPage(CharSequence title, View illustrationView, ImageView indicatorIcon,
|
||||
CharSequence instruction) {
|
||||
this.mTitle = title;
|
||||
this.mImageView = imageView;
|
||||
this.mIllustrationView = illustrationView;
|
||||
this.mIndicatorIcon = indicatorIcon;
|
||||
this.mInstruction = instruction;
|
||||
|
||||
setupIllustrationChildViewsGravity();
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public ImageView getImageView() {
|
||||
return mImageView;
|
||||
public View getIllustrationView() {
|
||||
return mIllustrationView;
|
||||
}
|
||||
|
||||
public ImageView getIndicatorIcon() {
|
||||
@@ -443,6 +508,23 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
public CharSequence getInstruction() {
|
||||
return mInstruction;
|
||||
}
|
||||
|
||||
private void setupIllustrationChildViewsGravity() {
|
||||
final View backgroundView = mIllustrationView.findViewById(R.id.image_background);
|
||||
initViewGravity(backgroundView);
|
||||
|
||||
final View lottieView = mIllustrationView.findViewById(R.id.image);
|
||||
initViewGravity(lottieView);
|
||||
}
|
||||
|
||||
private void initViewGravity(@NonNull View view) {
|
||||
final FrameLayout.LayoutParams layoutParams =
|
||||
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.gravity = Gravity.CENTER;
|
||||
|
||||
view.setLayoutParams(layoutParams);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TutorialPageChangeListener implements ViewPager.OnPageChangeListener {
|
||||
|
@@ -27,10 +27,10 @@ import com.android.settings.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/** LayerDrawable that contains device icon as background and floating menu icon as foreground. */
|
||||
public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
/** LayerDrawable that contains device icon as background and given icon as foreground. */
|
||||
public class AccessibilityLayerDrawable extends LayerDrawable {
|
||||
|
||||
private FloatingMenuLayerDrawableState mState;
|
||||
private AccessibilityLayerDrawableState mState;
|
||||
|
||||
/**
|
||||
* Creates a new layer drawable with the list of specified layers.
|
||||
@@ -38,23 +38,23 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
* @param layers a list of drawables to use as layers in this new drawable,
|
||||
* must be non-null
|
||||
*/
|
||||
private FloatingMenuLayerDrawable(@NonNull Drawable[] layers) {
|
||||
private AccessibilityLayerDrawable(@NonNull Drawable[] layers) {
|
||||
super(layers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link LayerDrawable} that contains device icon as background and floating menu
|
||||
* icon with given {@code opacity} value as foreground.
|
||||
* Create the {@link LayerDrawable} that contains device icon as background and given menu icon
|
||||
* with given {@code opacity} value as foreground.
|
||||
*
|
||||
* @param context the valid context used to get the icon
|
||||
* @param resId the resource ID of the floating menu icon
|
||||
* @param resId the resource ID of the given icon
|
||||
* @param opacity the opacity to apply to the given icon
|
||||
* @return the drawable that combines the device icon and the floating menu icon
|
||||
* @return the drawable that combines the device icon and the given icon
|
||||
*/
|
||||
public static FloatingMenuLayerDrawable createLayerDrawable(Context context, int resId,
|
||||
public static AccessibilityLayerDrawable createLayerDrawable(Context context, int resId,
|
||||
int opacity) {
|
||||
final Drawable bg = context.getDrawable(R.drawable.accessibility_button_preview_base);
|
||||
final FloatingMenuLayerDrawable basicDrawable = new FloatingMenuLayerDrawable(
|
||||
final AccessibilityLayerDrawable basicDrawable = new AccessibilityLayerDrawable(
|
||||
new Drawable[]{bg, null});
|
||||
|
||||
basicDrawable.updateLayerDrawable(context, resId, opacity);
|
||||
@@ -66,7 +66,7 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
* value at index 1 layer.
|
||||
*
|
||||
* @param context the valid context used to get the icon
|
||||
* @param resId the resource ID of the floating menu icon
|
||||
* @param resId the resource ID of the given icon
|
||||
* @param opacity the opacity to apply to the given icon
|
||||
*/
|
||||
public void updateLayerDrawable(Context context, int resId, int opacity) {
|
||||
@@ -83,18 +83,18 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
|
||||
/** Stores the constant state and data to the given drawable. */
|
||||
private void setConstantState(Context context, int resId, int opacity) {
|
||||
mState = new FloatingMenuLayerDrawableState(context, resId, opacity);
|
||||
mState = new AccessibilityLayerDrawableState(context, resId, opacity);
|
||||
}
|
||||
|
||||
/** {@link ConstantState} to store the data of {@link FloatingMenuLayerDrawable}. */
|
||||
/** {@link ConstantState} to store the data of {@link AccessibilityLayerDrawable}. */
|
||||
@VisibleForTesting
|
||||
static class FloatingMenuLayerDrawableState extends ConstantState {
|
||||
static class AccessibilityLayerDrawableState extends ConstantState {
|
||||
|
||||
private final Context mContext;
|
||||
private final int mResId;
|
||||
private final int mOpacity;
|
||||
|
||||
FloatingMenuLayerDrawableState(Context context, int resId, int opacity) {
|
||||
AccessibilityLayerDrawableState(Context context, int resId, int opacity) {
|
||||
mContext = context;
|
||||
mResId = resId;
|
||||
mOpacity = opacity;
|
||||
@@ -119,7 +119,7 @@ public class FloatingMenuLayerDrawable extends LayerDrawable {
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final FloatingMenuLayerDrawableState that = (FloatingMenuLayerDrawableState) o;
|
||||
final AccessibilityLayerDrawableState that = (AccessibilityLayerDrawableState) o;
|
||||
return mResId == that.mResId
|
||||
&& mOpacity == that.mOpacity
|
||||
&& Objects.equals(mContext, that.mContext);
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import android.content.ComponentName;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Provider for Accessibility metrics related features.
|
||||
*/
|
||||
public interface AccessibilityMetricsFeatureProvider {
|
||||
|
||||
/**
|
||||
* Returns {@link android.app.settings.SettingsEnums} value according to the {@code
|
||||
* componentName}.
|
||||
*
|
||||
* @param componentName the component name of the downloaded service or activity
|
||||
* @return value in {@link android.app.settings.SettingsEnums}
|
||||
*/
|
||||
int getDownloadedFeatureMetricsCategory(@Nullable ComponentName componentName);
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
|
||||
/**
|
||||
* Provider implementation for Accessibility metrics related features.
|
||||
*/
|
||||
public class AccessibilityMetricsFeatureProviderImpl implements
|
||||
AccessibilityMetricsFeatureProvider {
|
||||
|
||||
@Override
|
||||
public int getDownloadedFeatureMetricsCategory(ComponentName componentName) {
|
||||
return SettingsEnums.ACCESSIBILITY_SERVICE;
|
||||
}
|
||||
}
|
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.android.settings.core.SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.InstrumentedActivity;
|
||||
import com.android.settings.display.FontSizePreferenceFragmentForSetupWizard;
|
||||
import com.android.settings.display.ScreenZoomPreferenceFragmentForSetupWizard;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/** Settings font/display size activity for SUW. */
|
||||
public class AccessibilityScreenSizeForSetupWizardActivity extends InstrumentedActivity {
|
||||
private static final String TAG = "ScreenSizeForSetup";
|
||||
|
||||
// A parameter decides which fragment ({@link FontSizePreferenceFragmentForSetupWizard} or
|
||||
// {@link ScreenZoomPreferenceFragmentForSetupWizard}) will be visioned.
|
||||
static final String VISION_FRAGMENT_NO = "vision_fragment_no";
|
||||
/**
|
||||
* Flags indicating the type of the fragment.
|
||||
*/
|
||||
@IntDef({
|
||||
FragmentType.FONT_SIZE,
|
||||
FragmentType.SCREEN_SIZE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface FragmentType {
|
||||
int FONT_SIZE = 1;
|
||||
int SCREEN_SIZE = 2;
|
||||
}
|
||||
|
||||
// Keep the last height of the scroll view in the {@link GlifLayout}
|
||||
private int mLastScrollViewHeight;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final int appliedTheme = ThemeHelper.trySetDynamicColor(this)
|
||||
? R.style.SudDynamicColorThemeGlifV3_DayNight : R.style.SudThemeGlifV3_DayNight;
|
||||
setTheme(appliedTheme);
|
||||
setContentView(R.layout.accessibility_screen_size_setup_wizard);
|
||||
updateHeaderLayout();
|
||||
scrollToBottom();
|
||||
initFooterButton();
|
||||
if (savedInstanceState == null) {
|
||||
final PreferenceFragmentCompat fragment =
|
||||
getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? new FontSizePreferenceFragmentForSetupWizard()
|
||||
: new ScreenZoomPreferenceFragmentForSetupWizard();
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.content_frame, fragment)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
// For accessibility activities launched from setup wizard.
|
||||
if (getTransitionType(getIntent()) == TransitionType.TRANSITION_FADE) {
|
||||
overridePendingTransition(R.anim.sud_stay, android.R.anim.fade_out);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? SettingsEnums.SUW_ACCESSIBILITY_FONT_SIZE
|
||||
: SettingsEnums.SUW_ACCESSIBILITY_DISPLAY_SIZE;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateHeaderLayout() {
|
||||
if (ThemeHelper.shouldApplyExtendedPartnerConfig(this) && isSuwSupportedTwoPanes()) {
|
||||
final GlifLayout layout = findViewById(R.id.setup_wizard_layout);
|
||||
final LinearLayout headerLayout = layout.findManagedViewById(R.id.sud_layout_header);
|
||||
if (headerLayout != null) {
|
||||
headerLayout.setPadding(0, layout.getPaddingTop(), 0,
|
||||
layout.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
((TextView) findViewById(R.id.suc_layout_title)).setText(
|
||||
getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? R.string.title_font_size
|
||||
: R.string.screen_zoom_title);
|
||||
((TextView) findViewById(R.id.sud_layout_subtitle)).setText(
|
||||
getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? R.string.font_size_summary
|
||||
: R.string.screen_zoom_summary);
|
||||
}
|
||||
|
||||
private boolean isSuwSupportedTwoPanes() {
|
||||
return getResources().getBoolean(R.bool.config_suw_supported_two_panes);
|
||||
}
|
||||
|
||||
private void initFooterButton() {
|
||||
final GlifLayout layout = findViewById(R.id.setup_wizard_layout);
|
||||
final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
|
||||
final View.OnClickListener nextButtonListener = v -> onBackPressed();
|
||||
final FooterButton primaryButton =
|
||||
new FooterButton.Builder(this)
|
||||
.setText(R.string.done)
|
||||
.setListener(nextButtonListener)
|
||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build();
|
||||
mixin.setPrimaryButton(primaryButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls to bottom while {@link ScrollView} layout changed.
|
||||
*/
|
||||
private void scrollToBottom() {
|
||||
mLastScrollViewHeight = 0;
|
||||
final GlifLayout layout = findViewById(R.id.setup_wizard_layout);
|
||||
final ScrollView scrollView = layout.getScrollView();
|
||||
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
||||
final int scrollViewHeight = scrollView.getHeight();
|
||||
if (scrollViewHeight > 0 && scrollViewHeight != mLastScrollViewHeight) {
|
||||
mLastScrollViewHeight = scrollViewHeight;
|
||||
scrollView.post(() -> {
|
||||
// Here is no need to show the scrolling animation. So disabled first and
|
||||
// then enabled it after scrolling finished.
|
||||
scrollView.setSmoothScrollingEnabled(false);
|
||||
scrollView.fullScroll(View.FOCUS_DOWN);
|
||||
scrollView.setSmoothScrollingEnabled(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getTransitionType(Intent intent) {
|
||||
return intent.getIntExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_NONE);
|
||||
}
|
||||
|
||||
private int getFragmentType(Intent intent) {
|
||||
return intent.getIntExtra(VISION_FRAGMENT_NO, FragmentType.FONT_SIZE);
|
||||
}
|
||||
}
|
@@ -28,29 +28,29 @@ import android.content.pm.ServiceInfo;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity with the accessibility settings specific to Setup Wizard.
|
||||
*/
|
||||
public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragment
|
||||
public class AccessibilitySettingsForSetupWizard extends DashboardFragment
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
private static final String TAG = "AccessibilitySettingsForSetupWizard";
|
||||
|
||||
// Preferences.
|
||||
private static final String DISPLAY_MAGNIFICATION_PREFERENCE =
|
||||
@@ -81,16 +81,11 @@ public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragm
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
|
||||
layout.setDividerInsets(Integer.MAX_VALUE, 0);
|
||||
layout.setDescriptionText(R.string.vision_settings_description);
|
||||
layout.setHeaderText(R.string.vision_settings_title);
|
||||
layout.setIcon(getPrefContext().getDrawable(R.drawable.ic_accessibility_visibility));
|
||||
|
||||
if (ThemeHelper.shouldApplyExtendedPartnerConfig(getActivity())) {
|
||||
final LinearLayout headerLayout = layout.findManagedViewById(R.id.sud_layout_header);
|
||||
headerLayout.setPadding(0, headerLayout.getPaddingTop(), 0,
|
||||
headerLayout.getPaddingBottom());
|
||||
}
|
||||
final String title = getContext().getString(R.string.vision_settings_title);
|
||||
final String description = getContext().getString(R.string.vision_settings_description);
|
||||
final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
|
||||
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
|
||||
description, icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,8 +98,6 @@ public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragm
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
addPreferencesFromResource(R.xml.accessibility_settings_for_setup_wizard);
|
||||
|
||||
mDisplayMagnificationPreference = findPreference(DISPLAY_MAGNIFICATION_PREFERENCE);
|
||||
mScreenReaderPreference = findPreference(SCREEN_READER_PREFERENCE);
|
||||
mSelectToSpeakPreference = findPreference(SELECT_TO_SPEAK_PREFERENCE);
|
||||
@@ -143,6 +136,23 @@ public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragm
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accessibility_settings_for_setup_wizard;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns accessibility service info by given package name and service name.
|
||||
*
|
||||
* @param packageName Package of accessibility service
|
||||
* @param serviceName Class of accessibility service
|
||||
* @return {@link AccessibilityServiceInfo} instance if available, null otherwise.
|
||||
*/
|
||||
private AccessibilityServiceInfo findService(String packageName, String serviceName) {
|
||||
final AccessibilityManager manager =
|
||||
getActivity().getSystemService(AccessibilityManager.class);
|
||||
@@ -150,8 +160,8 @@ public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragm
|
||||
manager.getInstalledAccessibilityServiceList();
|
||||
for (AccessibilityServiceInfo info : accessibilityServices) {
|
||||
ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
|
||||
if (packageName.equals(serviceInfo.packageName)
|
||||
&& serviceName.equals(serviceInfo.name)) {
|
||||
if (TextUtils.equals(packageName, serviceInfo.packageName)
|
||||
&& TextUtils.equals(serviceName, serviceInfo.name)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.VISION_FRAGMENT_NO;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
@@ -29,8 +32,8 @@ import androidx.preference.PreferenceFragmentCompat;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.FragmentType;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.display.FontSizePreferenceFragmentForSetupWizard;
|
||||
import com.android.settings.search.actionbar.SearchMenuController;
|
||||
import com.android.settings.support.actionbar.HelpResourceProvider;
|
||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||
@@ -123,19 +126,11 @@ public class AccessibilitySettingsForSetupWizardActivity extends SettingsActivit
|
||||
&& new ComponentName(getPackageName(),
|
||||
CLASS_NAME_FONT_SIZE_SETTINGS_FOR_SUW).equals(
|
||||
getIntent().getComponent())) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putInt(HelpResourceProvider.HELP_URI_RESOURCE_KEY, 0);
|
||||
args.putBoolean(SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR, false);
|
||||
final SubSettingLauncher subSettingLauncher = new SubSettingLauncher(this)
|
||||
.setDestination(FontSizePreferenceFragmentForSetupWizard.class.getName())
|
||||
.setArguments(args)
|
||||
.setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN)
|
||||
.setExtras(SetupWizardUtils.copyLifecycleExtra(getIntent().getExtras(),
|
||||
new Bundle()))
|
||||
.setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_FADE);
|
||||
|
||||
final Intent intent = new Intent(this,
|
||||
AccessibilityScreenSizeForSetupWizardActivity.class);
|
||||
intent.putExtra(VISION_FRAGMENT_NO, FragmentType.FONT_SIZE);
|
||||
startActivity(intent);
|
||||
Log.d(LOG_TAG, "Launch font size settings");
|
||||
subSettingLauncher.launch();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
/** Provides utility methods to accessibility settings for Setup Wizard only. */
|
||||
class AccessibilitySetupWizardUtils {
|
||||
|
||||
private AccessibilitySetupWizardUtils(){}
|
||||
|
||||
/**
|
||||
* Update the {@link GlifPreferenceLayout} attributes if they have previously been initialized.
|
||||
* When the SetupWizard supports the extended partner configs, it means the material layout
|
||||
* would be applied. It should set a different padding/margin in views to align Settings style
|
||||
* for accessibility feature pages.
|
||||
*
|
||||
* @param layout The layout instance
|
||||
* @param title The text to be set as title
|
||||
* @param description The text to be set as description
|
||||
* @param icon The icon to be set
|
||||
*/
|
||||
public static void updateGlifPreferenceLayout(Context context, GlifPreferenceLayout layout,
|
||||
CharSequence title, CharSequence description, Drawable icon) {
|
||||
layout.setHeaderText(title);
|
||||
layout.setDescriptionText(description);
|
||||
layout.setIcon(icon);
|
||||
layout.setDividerInsets(Integer.MAX_VALUE, 0);
|
||||
|
||||
if (ThemeHelper.shouldApplyExtendedPartnerConfig(context)) {
|
||||
final LinearLayout headerLayout = layout.findManagedViewById(R.id.sud_layout_header);
|
||||
if (headerLayout != null) {
|
||||
headerLayout.setPadding(0, layout.getPaddingTop(), 0,
|
||||
layout.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@ import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/**
|
||||
@@ -57,4 +58,9 @@ public class AccessibilityShortcutPreferenceController extends TogglePreferenceC
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -115,8 +115,7 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
mShortcutPreference.setKey(getShortcutPreferenceKey());
|
||||
mShortcutPreference.setOnClickCallback(this);
|
||||
|
||||
final CharSequence title = getString(R.string.accessibility_shortcut_title, getLabelName());
|
||||
mShortcutPreference.setTitle(title);
|
||||
updateShortcutTitle(mShortcutPreference);
|
||||
getPreferenceScreen().addPreference(mShortcutPreference);
|
||||
|
||||
mTouchExplorationStateChangeListener = isTouchExplorationEnabled -> {
|
||||
@@ -182,6 +181,11 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
final CharSequence title = getString(R.string.accessibility_shortcut_title, getLabelName());
|
||||
shortcutPreference.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDialogMetricsCategory(int dialogId) {
|
||||
switch (dialogId) {
|
||||
|
@@ -26,6 +26,7 @@ import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
|
||||
@@ -98,6 +99,11 @@ public class AccessibilitySlicePreferenceController extends TogglePreferenceCont
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
private AccessibilityServiceInfo getAccessibilityServiceInfo() {
|
||||
final AccessibilityManager accessibilityManager = mContext.getSystemService(
|
||||
AccessibilityManager.class);
|
||||
|
@@ -17,16 +17,22 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
|
||||
import static android.view.WindowInsets.Type.displayCutout;
|
||||
import static android.view.WindowInsets.Type.systemBars;
|
||||
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowMetrics;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
@@ -390,6 +396,25 @@ final class AccessibilityUtil {
|
||||
resources.getDisplayMetrics()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bounds of the display window excluding the insets of the system bar and display
|
||||
* cut out.
|
||||
*
|
||||
* @param context the current context.
|
||||
* @return the bounds of the display window.
|
||||
*/
|
||||
public static Rect getDisplayBounds(Context context) {
|
||||
final WindowManager windowManager = context.getSystemService(WindowManager.class);
|
||||
final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
|
||||
|
||||
final Rect displayBounds = metrics.getBounds();
|
||||
final Insets displayInsets = metrics.getWindowInsets().getInsetsIgnoringVisibility(
|
||||
systemBars() | displayCutout());
|
||||
displayBounds.inset(displayInsets);
|
||||
|
||||
return displayBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the accessibility service belongs to a system App.
|
||||
* @param info AccessibilityServiceInfo
|
||||
|
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static android.view.HapticFeedbackConstants.CLOCK_TICK;
|
||||
|
||||
import static com.android.settings.Utils.isNightMode;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -154,7 +155,7 @@ public class BalanceSeekBar extends SeekBar {
|
||||
// Draw a vertical line at 50% that represents centred balance
|
||||
int seekBarCenter = (canvas.getHeight() - getPaddingBottom()) / 2;
|
||||
canvas.save();
|
||||
canvas.translate((canvas.getWidth() - mCenterMarkerRect.right) / 2,
|
||||
canvas.translate((canvas.getWidth() - mCenterMarkerRect.right - getPaddingEnd()) / 2,
|
||||
seekBarCenter - (mCenterMarkerRect.bottom / 2));
|
||||
canvas.drawRect(mCenterMarkerRect, mCenterMarkerPaint);
|
||||
canvas.restore();
|
||||
|
@@ -30,12 +30,18 @@ public class CaptionFooterPreferenceController extends AccessibilityFooterPrefer
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLabelName() {
|
||||
return mContext.getString(R.string.accessibility_captioning_title);
|
||||
protected String getLearnMoreContentDescription() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_captioning_footer_learn_more_content_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHelpResource() {
|
||||
protected String getIntroductionTitle() {
|
||||
return mContext.getString(R.string.accessibility_captioning_about_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHelpResource() {
|
||||
return R.string.help_url_caption;
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class DisableAnimationsPreferenceController extends TogglePreferenceController {
|
||||
@@ -71,4 +72,9 @@ public class DisableAnimationsPreferenceController extends TogglePreferenceContr
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.VISION_FRAGMENT_NO;
|
||||
import static com.android.settings.core.SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.FragmentType;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
|
||||
|
||||
/** PreferenceController for displaying font size page. */
|
||||
public class FontSizePreferenceController extends BasePreferenceController {
|
||||
|
||||
public FontSizePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!mPreferenceKey.equals(preference.getKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(mContext,
|
||||
AccessibilityScreenSizeForSetupWizardActivity.class);
|
||||
intent.putExtra(VISION_FRAGMENT_NO, FragmentType.FONT_SIZE);
|
||||
intent.putExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_FADE);
|
||||
mContext.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.graphics.fonts.FontStyle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** PreferenceController for displaying all text in bold. */
|
||||
@@ -47,4 +48,9 @@ public class FontWeightAdjustmentPreferenceController extends TogglePreferenceCo
|
||||
return Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.FONT_WEIGHT_ADJUSTMENT, (isChecked ? BOLD_TEXT_ADJUSTMENT : 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ package com.android.settings.accessibility;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class HighTextContrastPreferenceController extends TogglePreferenceController {
|
||||
@@ -43,4 +44,9 @@ public class HighTextContrastPreferenceController extends TogglePreferenceContro
|
||||
return Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, (isChecked ? 1 : 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class LargePointerIconPreferenceController extends TogglePreferenceController {
|
||||
@@ -50,4 +51,9 @@ public class LargePointerIconPreferenceController extends TogglePreferenceContro
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -41,6 +41,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -51,6 +52,19 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
private static final String EMPTY_STRING = "";
|
||||
protected static final String KEY_LAUNCH_PREFERENCE = "launch_preference";
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
// Retrieve from getArguments() directly because this function will be executed from
|
||||
// onAttach(), but variable mComponentName only available after onProcessArguments()
|
||||
// which comes from onCreateView().
|
||||
final ComponentName componentName = getArguments().getParcelable(
|
||||
AccessibilitySettings.EXTRA_COMPONENT_NAME);
|
||||
|
||||
return FeatureFactory.getFactory(getActivity().getApplicationContext())
|
||||
.getAccessibilityMetricsFeatureProvider()
|
||||
.getDownloadedFeatureMetricsCategory(componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
@@ -60,7 +74,7 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
initLaunchPreference();
|
||||
removePreference(KEY_USE_SERVICE_PREFERENCE);
|
||||
return view;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
@@ -70,7 +84,6 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
@Override
|
||||
protected void onProcessArguments(Bundle arguments) {
|
||||
super.onProcessArguments(arguments);
|
||||
|
||||
mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
|
||||
final ActivityInfo info = getAccessibilityShortcutInfo().getActivityInfo();
|
||||
mPackageName = info.loadLabel(getPackageManager()).toString();
|
||||
@@ -137,6 +150,7 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
|
||||
private void initLaunchPreference() {
|
||||
final Preference launchPreference = new Preference(getPrefContext());
|
||||
launchPreference.setLayoutResource(R.layout.accessibility_launch_activity_preference);
|
||||
launchPreference.setKey(KEY_LAUNCH_PREFERENCE);
|
||||
|
||||
final AccessibilityShortcutInfo info = getAccessibilityShortcutInfo();
|
||||
|
@@ -23,6 +23,7 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.view.RotationPolicy;
|
||||
import com.android.internal.view.RotationPolicy.RotationPolicyListener;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
@@ -61,6 +62,11 @@ public class LockScreenRotationPreferenceController extends TogglePreferenceCont
|
||||
return RotationPolicy.isRotationSupported(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (mRotationPolicyListener != null) {
|
||||
|
@@ -76,6 +76,11 @@ public class MagnificationGesturesPreferenceController extends TogglePreferenceC
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
int resId = 0;
|
||||
|
@@ -82,6 +82,11 @@ public class MagnificationNavbarPreferenceController extends TogglePreferenceCon
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
int resId = 0;
|
||||
|
@@ -21,6 +21,7 @@ import android.provider.Settings;
|
||||
import android.view.KeyCharacterMap;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
@@ -51,4 +52,9 @@ public class PowerButtonEndsCallPreferenceController extends TogglePreferenceCon
|
||||
return !KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
|
||||
|| !Utils.isVoiceCapable(mContext) ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/**
|
||||
@@ -47,4 +48,9 @@ public class PrimaryMonoPreferenceController extends TogglePreferenceController
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import android.provider.Settings;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** PreferenceController for persisting feature activation state after a restart. */
|
||||
@@ -62,4 +63,9 @@ public class ReduceBrightColorsPersistencePreferenceController extends TogglePre
|
||||
super.updateState(preference);
|
||||
preference.setEnabled(mColorDisplayManager.isReduceBrightColorsActivated());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
|
@@ -94,6 +94,11 @@ public class ReduceBrightColorsPreferenceController extends TogglePreferenceCont
|
||||
mPreference = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
|
||||
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.VISION_FRAGMENT_NO;
|
||||
import static com.android.settings.core.SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.FragmentType;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
|
||||
|
||||
/** PreferenceController for displaying screen size page. */
|
||||
public class ScreenSizePreferenceController extends BasePreferenceController {
|
||||
|
||||
public ScreenSizePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!mPreferenceKey.equals(preference.getKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(mContext,
|
||||
AccessibilityScreenSizeForSetupWizardActivity.class);
|
||||
intent.putExtra(VISION_FRAGMENT_NO, FragmentType.SCREEN_SIZE);
|
||||
intent.putExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_FADE);
|
||||
mContext.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -54,8 +54,8 @@ import androidx.annotation.Nullable;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ConfirmDeviceCredentialActivity;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
|
||||
import java.util.List;
|
||||
@@ -85,7 +85,15 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCESSIBILITY_SERVICE;
|
||||
// Retrieve from getArguments() directly because this function will be executed from
|
||||
// onAttach(), but variable mComponentName only available after onProcessArguments()
|
||||
// which comes from onCreateView().
|
||||
final ComponentName componentName = getArguments().getParcelable(
|
||||
AccessibilitySettings.EXTRA_COMPONENT_NAME);
|
||||
|
||||
return FeatureFactory.getFactory(getActivity().getApplicationContext())
|
||||
.getAccessibilityMetricsFeatureProvider()
|
||||
.getDownloadedFeatureMetricsCategory(componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -221,15 +229,6 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateToggleServiceTitle(SettingsMainSwitchPreference switchPreference) {
|
||||
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
final String switchBarText = (info == null) ? "" :
|
||||
getString(R.string.accessibility_service_primary_switch_title,
|
||||
info.getResolveInfo().loadLabel(getPackageManager()));
|
||||
switchPreference.setTitle(switchBarText);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSwitchBarToggleSwitch() {
|
||||
final boolean checked = isAccessibilityServiceEnabled();
|
||||
|
@@ -31,8 +31,14 @@ public class ToggleAutoclickFooterPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLabelName() {
|
||||
return mContext.getString(R.string.accessibility_autoclick_preference_title);
|
||||
protected String getLearnMoreContentDescription() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_autoclick_footer_learn_more_content_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIntroductionTitle() {
|
||||
return mContext.getString(R.string.accessibility_autoclick_about_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -38,8 +38,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Settings page for color inversion. */
|
||||
public class ToggleColorInversionPreferenceFragment extends
|
||||
ToggleFeaturePreferenceFragment {
|
||||
public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePreferenceFragment {
|
||||
|
||||
private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED;
|
||||
private final Handler mHandler = new Handler();
|
||||
@@ -72,6 +71,11 @@ public class ToggleColorInversionPreferenceFragment extends
|
||||
switchPreference.setTitle(R.string.accessibility_display_inversion_switch_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.accessibility_display_inversion_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
@@ -90,7 +94,20 @@ public class ToggleColorInversionPreferenceFragment extends
|
||||
updateSwitchBarToggleSwitch();
|
||||
}
|
||||
};
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
updateFooterPreference();
|
||||
return view;
|
||||
}
|
||||
|
||||
private void updateFooterPreference() {
|
||||
final String title = getPrefContext().getString(
|
||||
R.string.accessibility_color_inversion_about_title);
|
||||
final String learnMoreContentDescription = getPrefContext().getString(
|
||||
R.string.accessibility_color_inversion_footer_learn_more_content_description);
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreContentDescription);
|
||||
mFooterPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -92,12 +92,20 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
updateSwitchBarToggleSwitch();
|
||||
}
|
||||
};
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
updateFooterPreference();
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
private void updateFooterPreference() {
|
||||
final String title = getPrefContext()
|
||||
.getString(R.string.accessibility_daltonizer_about_title);
|
||||
final String learnMoreContentDescription = getPrefContext()
|
||||
.getString(R.string.accessibility_daltonizer_footer_learn_more_content_description);
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreContentDescription);
|
||||
mFooterPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
/** Customizes the order by preference key. */
|
||||
@@ -167,6 +175,11 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
switchPreference.setTitle(R.string.accessibility_daltonizer_primary_switch_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.accessibility_daltonizer_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getUserShortcutTypes() {
|
||||
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
|
||||
|
@@ -57,7 +57,6 @@ import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.HelpUtils;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
import com.android.settingslib.widget.IllustrationPreference;
|
||||
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
||||
@@ -78,7 +77,9 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
protected SettingsMainSwitchPreference mToggleServiceSwitchPreference;
|
||||
protected ShortcutPreference mShortcutPreference;
|
||||
protected Preference mSettingsPreference;
|
||||
protected AccessibilityFooterPreferenceController mFooterPreferenceController;
|
||||
protected String mPreferenceKey;
|
||||
protected Dialog mDialog;
|
||||
|
||||
protected CharSequence mSettingsTitle;
|
||||
protected Intent mSettingsIntent;
|
||||
@@ -106,6 +107,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
public static final int NOT_SET = -1;
|
||||
// Save user's shortcutType value when savedInstance has value (e.g. device rotated).
|
||||
protected int mSavedCheckBoxValue = NOT_SET;
|
||||
private boolean mSavedAccessibilityFloatingMenuEnabled;
|
||||
|
||||
// For html description of accessibility service, must follow the rule, such as
|
||||
// <img src="R.drawable.fileName"/>, a11y settings will get the resources successfully.
|
||||
@@ -127,7 +129,6 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Restore the user shortcut type.
|
||||
if (savedInstanceState != null && savedInstanceState.containsKey(
|
||||
KEY_SAVED_USER_SHORTCUT_TYPE)) {
|
||||
@@ -142,9 +143,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
setPreferenceScreen(preferenceScreen);
|
||||
}
|
||||
|
||||
final List<String> shortcutFeatureKeys = new ArrayList<>();
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
final List<String> shortcutFeatureKeys = getFeatureSettingsKeys();
|
||||
mSettingsContentObserver = new SettingsContentObserver(new Handler(), shortcutFeatureKeys) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
@@ -154,6 +153,13 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
};
|
||||
}
|
||||
|
||||
protected List<String> getFeatureSettingsKeys() {
|
||||
final List<String> shortcutFeatureKeys = new ArrayList<>();
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
return shortcutFeatureKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
@@ -200,6 +206,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
mSettingsContentObserver.register(getContentResolver());
|
||||
updateShortcutPreferenceData();
|
||||
updateShortcutPreference();
|
||||
|
||||
updateEditShortcutDialogIfNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -208,6 +216,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
AccessibilityManager.class);
|
||||
am.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
|
||||
mSettingsContentObserver.unregister(getContentResolver());
|
||||
mSavedAccessibilityFloatingMenuEnabled = AccessibilityUtil.isFloatingMenuEnabled(
|
||||
getContext());
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@@ -222,24 +232,23 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(int dialogId) {
|
||||
Dialog dialog;
|
||||
switch (dialogId) {
|
||||
case DialogEnums.EDIT_SHORTCUT:
|
||||
final CharSequence dialogTitle = getPrefContext().getString(
|
||||
R.string.accessibility_shortcut_title, mPackageName);
|
||||
final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
|
||||
? DialogType.EDIT_SHORTCUT_GENERIC_SUW : DialogType.EDIT_SHORTCUT_GENERIC;
|
||||
dialog = AccessibilityDialogUtils.showEditShortcutDialog(
|
||||
mDialog = AccessibilityDialogUtils.showEditShortcutDialog(
|
||||
getPrefContext(), dialogType, dialogTitle,
|
||||
this::callOnAlertDialogCheckboxClicked);
|
||||
setupEditShortcutDialog(dialog);
|
||||
return dialog;
|
||||
setupEditShortcutDialog(mDialog);
|
||||
return mDialog;
|
||||
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
|
||||
dialog = AccessibilityGestureNavigationTutorial
|
||||
mDialog = AccessibilityGestureNavigationTutorial
|
||||
.createAccessibilityTutorialDialog(getPrefContext(),
|
||||
getUserShortcutTypes());
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
return dialog;
|
||||
mDialog.setCanceledOnTouchOutside(false);
|
||||
return mDialog;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
|
||||
}
|
||||
@@ -284,7 +293,14 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
abstract int getUserShortcutTypes();
|
||||
|
||||
protected void updateToggleServiceTitle(SettingsMainSwitchPreference switchPreference) {
|
||||
switchPreference.setTitle(R.string.accessibility_service_primary_switch_title);
|
||||
final CharSequence title =
|
||||
getString(R.string.accessibility_service_primary_switch_title, mPackageName);
|
||||
switchPreference.setTitle(title);
|
||||
}
|
||||
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
final CharSequence title = getString(R.string.accessibility_shortcut_title, mPackageName);
|
||||
shortcutPreference.setTitle(title);
|
||||
}
|
||||
|
||||
protected abstract void onPreferenceToggled(String preferenceKey, boolean enabled);
|
||||
@@ -399,10 +415,13 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
return;
|
||||
}
|
||||
|
||||
final int displayHalfHeight =
|
||||
AccessibilityUtil.getDisplayBounds(getPrefContext()).height() / 2;
|
||||
final IllustrationPreference illustrationPreference =
|
||||
new IllustrationPreference(getPrefContext());
|
||||
illustrationPreference.setImageUri(mImageUri);
|
||||
illustrationPreference.setSelectable(false);
|
||||
illustrationPreference.setMaxHeight(displayHalfHeight);
|
||||
illustrationPreference.setKey(KEY_ANIMATED_IMAGE);
|
||||
|
||||
getPreferenceScreen().addPreference(illustrationPreference);
|
||||
@@ -434,8 +453,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
mShortcutPreference.setKey(getShortcutPreferenceKey());
|
||||
mShortcutPreference.setOnClickCallback(this);
|
||||
|
||||
final CharSequence title = getString(R.string.accessibility_shortcut_title, mPackageName);
|
||||
mShortcutPreference.setTitle(title);
|
||||
updateShortcutTitle(mShortcutPreference);
|
||||
|
||||
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
|
||||
generalCategory.addPreference(mShortcutPreference);
|
||||
@@ -463,33 +481,19 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
final PreferenceScreen screen = getPreferenceScreen();
|
||||
final CharSequence htmlDescription = Html.fromHtml(mHtmlDescription.toString(),
|
||||
Html.FROM_HTML_MODE_COMPACT, mImageGetter, /* tagHandler= */ null);
|
||||
final String iconContentDescription =
|
||||
getString(R.string.accessibility_introduction_title, mPackageName);
|
||||
|
||||
final AccessibilityFooterPreference htmlFooterPreference =
|
||||
new AccessibilityFooterPreference(screen.getContext());
|
||||
htmlFooterPreference.setKey(KEY_HTML_DESCRIPTION_PREFERENCE);
|
||||
htmlFooterPreference.setSummary(htmlDescription);
|
||||
htmlFooterPreference.setContentDescription(
|
||||
generateFooterContentDescription(htmlDescription));
|
||||
|
||||
// Only framework tools support help link
|
||||
if (getHelpResource() != 0) {
|
||||
htmlFooterPreference.setLearnMoreAction(view -> {
|
||||
final Intent helpIntent = HelpUtils.getHelpIntent(
|
||||
getContext(), getContext().getString(getHelpResource()),
|
||||
getContext().getClass().getName());
|
||||
view.startActivityForResult(helpIntent, 0);
|
||||
});
|
||||
|
||||
final String learnMoreContentDescription = getPrefContext().getString(
|
||||
R.string.footer_learn_more_content_description, mPackageName);
|
||||
htmlFooterPreference.setLearnMoreContentDescription(learnMoreContentDescription);
|
||||
htmlFooterPreference.setLinkEnabled(true);
|
||||
} else {
|
||||
htmlFooterPreference.setLinkEnabled(false);
|
||||
}
|
||||
screen.addPreference(htmlFooterPreference);
|
||||
|
||||
// TODO(b/171272809): Migrate to DashboardFragment.
|
||||
final String title = getString(R.string.accessibility_introduction_title, mPackageName);
|
||||
mFooterPreferenceController = new AccessibilityFooterPreferenceController(
|
||||
screen.getContext(), htmlFooterPreference.getKey());
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.displayPreference(screen);
|
||||
}
|
||||
|
||||
private void initFooterPreference() {
|
||||
@@ -512,41 +516,22 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
*
|
||||
* @param screen The preference screen to add the footer preference
|
||||
* @param summary The summary of the preference summary.
|
||||
* @param iconContentDescription The content description of icon in the footer.
|
||||
* @param introductionTitle The title of introduction in the footer.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void createFooterPreference(PreferenceScreen screen, CharSequence summary,
|
||||
String iconContentDescription) {
|
||||
String introductionTitle) {
|
||||
final AccessibilityFooterPreference footerPreference =
|
||||
new AccessibilityFooterPreference(screen.getContext());
|
||||
footerPreference.setSummary(summary);
|
||||
footerPreference.setContentDescription(
|
||||
generateFooterContentDescription(summary));
|
||||
|
||||
// Only framework tools support help link
|
||||
if (getHelpResource() != 0) {
|
||||
footerPreference.setLearnMoreAction(view -> {
|
||||
final Intent helpIntent = HelpUtils.getHelpIntent(
|
||||
getContext(), getContext().getString(getHelpResource()),
|
||||
getContext().getClass().getName());
|
||||
view.startActivityForResult(helpIntent, 0);
|
||||
});
|
||||
|
||||
final String learnMoreContentDescription = getPrefContext().getString(
|
||||
R.string.footer_learn_more_content_description, mPackageName);
|
||||
footerPreference.setLearnMoreContentDescription(learnMoreContentDescription);
|
||||
}
|
||||
screen.addPreference(footerPreference);
|
||||
|
||||
mFooterPreferenceController = new AccessibilityFooterPreferenceController(
|
||||
screen.getContext(), footerPreference.getKey());
|
||||
mFooterPreferenceController.setIntroductionTitle(introductionTitle);
|
||||
mFooterPreferenceController.displayPreference(screen);
|
||||
}
|
||||
|
||||
private CharSequence generateFooterContentDescription(CharSequence footerContent) {
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
sb.append(getPrefContext().getString(
|
||||
R.string.accessibility_introduction_title, mPackageName))
|
||||
.append("\n\n")
|
||||
.append(footerContent);
|
||||
return sb;
|
||||
}
|
||||
@VisibleForTesting
|
||||
void setupEditShortcutDialog(Dialog dialog) {
|
||||
final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut);
|
||||
@@ -611,6 +596,18 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
return value;
|
||||
}
|
||||
|
||||
private static CharSequence getSoftwareShortcutTypeSummary(Context context) {
|
||||
int resId;
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
resId = R.string.accessibility_shortcut_edit_summary_software;
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
resId = R.string.accessibility_shortcut_edit_summary_software_gesture;
|
||||
} else {
|
||||
resId = R.string.accessibility_shortcut_edit_summary_software;
|
||||
}
|
||||
return context.getText(resId);
|
||||
}
|
||||
|
||||
protected CharSequence getShortcutTypeSummary(Context context) {
|
||||
if (!mShortcutPreference.isSettingsEditable()) {
|
||||
return context.getText(R.string.accessibility_shortcut_edit_dialog_title_hardware);
|
||||
@@ -624,11 +621,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
|
||||
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
final CharSequence softwareTitle = context.getText(
|
||||
R.string.accessibility_shortcut_edit_summary_software);
|
||||
|
||||
if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
|
||||
list.add(softwareTitle);
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
|
||||
final CharSequence hardwareTitle = context.getText(
|
||||
@@ -638,7 +632,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
|
||||
// Show software shortcut if first time to use.
|
||||
if (list.isEmpty()) {
|
||||
list.add(softwareTitle);
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
|
||||
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
|
||||
@@ -748,6 +742,20 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
}
|
||||
}
|
||||
|
||||
private void updateEditShortcutDialogIfNeeded() {
|
||||
if (mDialog == null || !mDialog.isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Content in software shortcut need to be adjusted depend on the accessibility button
|
||||
// mode status which can be changed in background.
|
||||
final boolean valueChanged = mSavedAccessibilityFloatingMenuEnabled
|
||||
!= AccessibilityUtil.isFloatingMenuEnabled(getContext());
|
||||
if (valueChanged) {
|
||||
AccessibilityDialogUtils.updateSoftwareShortcutInDialog(getContext(), mDialog);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void saveNonEmptyUserShortcutType(int type) {
|
||||
if (type == UserShortcutType.EMPTY) {
|
||||
|
@@ -86,6 +86,7 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
// Parent sets the title when creating the view, so set it after calling super
|
||||
mToggleServiceSwitchPreference.setTitle(R.string.reduce_bright_colors_switch_title);
|
||||
updateGeneralCategoryOrder();
|
||||
updateFooterPreference();
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -101,6 +102,12 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
generalCategory.addPreference(persist);
|
||||
}
|
||||
|
||||
private void updateFooterPreference() {
|
||||
final String title = getPrefContext().getString(R.string.reduce_bright_colors_about_title);
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
@@ -135,7 +142,6 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
return R.xml.reduce_bright_colors_settings;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
AccessibilityStatsLogUtils.logAccessibilityServiceEnabled(mComponentName, enabled);
|
||||
@@ -154,6 +160,11 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
switchPreference.setTitle(R.string.reduce_bright_colors_preference_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.reduce_bright_colors_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getUserShortcutTypes() {
|
||||
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
|
||||
|
@@ -38,7 +38,6 @@ import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
|
||||
import android.widget.CheckBox;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
|
||||
@@ -95,7 +94,20 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
removeDialog(DialogEnums.EDIT_SHORTCUT);
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
};
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
updateFooterPreference();
|
||||
return view;
|
||||
}
|
||||
|
||||
private void updateFooterPreference() {
|
||||
final String title = getPrefContext().getString(
|
||||
R.string.accessibility_screen_magnification_about_title);
|
||||
final String learnMoreContentDescription = getPrefContext().getString(
|
||||
R.string.accessibility_screen_magnification_footer_learn_more_content_description);
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreContentDescription);
|
||||
mFooterPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,26 +131,25 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
@Override
|
||||
public Dialog onCreateDialog(int dialogId) {
|
||||
if (mDialogDelegate != null) {
|
||||
final Dialog dialog = mDialogDelegate.onCreateDialog(dialogId);
|
||||
if (dialog != null) {
|
||||
return dialog;
|
||||
mDialog = mDialogDelegate.onCreateDialog(dialogId);
|
||||
if (mDialog != null) {
|
||||
return mDialog;
|
||||
}
|
||||
}
|
||||
final AlertDialog dialog;
|
||||
switch (dialogId) {
|
||||
case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
|
||||
return AccessibilityGestureNavigationTutorial
|
||||
.showGestureNavigationTutorialDialog(getPrefContext());
|
||||
.showAccessibilityGestureTutorialDialog(getPrefContext());
|
||||
case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT:
|
||||
final CharSequence dialogTitle = getPrefContext().getString(
|
||||
R.string.accessibility_shortcut_title, mPackageName);
|
||||
final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
|
||||
? DialogType.EDIT_SHORTCUT_MAGNIFICATION_SUW
|
||||
: DialogType.EDIT_SHORTCUT_MAGNIFICATION;
|
||||
dialog = AccessibilityDialogUtils.showEditShortcutDialog(getPrefContext(),
|
||||
mDialog = AccessibilityDialogUtils.showEditShortcutDialog(getPrefContext(),
|
||||
dialogType, dialogTitle, this::callOnAlertDialogCheckboxClicked);
|
||||
setupMagnificationEditShortcutDialog(dialog);
|
||||
return dialog;
|
||||
setupMagnificationEditShortcutDialog(mDialog);
|
||||
return mDialog;
|
||||
default:
|
||||
return super.onCreateDialog(dialogId);
|
||||
}
|
||||
@@ -196,7 +207,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setupMagnificationEditShortcutDialog(AlertDialog dialog) {
|
||||
void setupMagnificationEditShortcutDialog(Dialog dialog) {
|
||||
final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut);
|
||||
mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox);
|
||||
setDialogTextAreaClickListener(dialogSoftwareView, mSoftwareTypeCheckBox);
|
||||
@@ -252,6 +263,25 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
return (value & type) == type;
|
||||
}
|
||||
|
||||
private static CharSequence getSoftwareShortcutTypeSummary(Context context) {
|
||||
int resId;
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
resId = R.string.accessibility_shortcut_edit_summary_software;
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
resId = R.string.accessibility_shortcut_edit_summary_software_gesture;
|
||||
} else {
|
||||
resId = R.string.accessibility_shortcut_edit_summary_software;
|
||||
}
|
||||
return context.getText(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getFeatureSettingsKeys() {
|
||||
final List<String> shortcutKeys = super.getFeatureSettingsKeys();
|
||||
shortcutKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
|
||||
return shortcutKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence getShortcutTypeSummary(Context context) {
|
||||
if (!mShortcutPreference.isChecked()) {
|
||||
@@ -262,18 +292,14 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
|
||||
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
final CharSequence softwareTitle = context.getText(
|
||||
R.string.accessibility_shortcut_edit_summary_software);
|
||||
|
||||
if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) {
|
||||
list.add(softwareTitle);
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) {
|
||||
final CharSequence hardwareTitle = context.getText(
|
||||
R.string.accessibility_shortcut_hardware_keyword);
|
||||
list.add(hardwareTitle);
|
||||
}
|
||||
|
||||
if (hasShortcutType(shortcutTypes, UserShortcutType.TRIPLETAP)) {
|
||||
final CharSequence tripleTapTitle = context.getText(
|
||||
R.string.accessibility_shortcut_triple_tap_keyword);
|
||||
@@ -282,7 +308,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
|
||||
// Show software shortcut if first time to use.
|
||||
if (list.isEmpty()) {
|
||||
list.add(softwareTitle);
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
|
||||
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
|
||||
@@ -396,6 +422,11 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
generalCategory.addPreference(mShortcutPreference);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.accessibility_screen_magnification_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutPreference() {
|
||||
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
|
||||
|
@@ -17,12 +17,45 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
|
||||
public class ToggleScreenMagnificationPreferenceFragmentForSetupWizard
|
||||
extends ToggleScreenMagnificationPreferenceFragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
|
||||
final String title = getContext().getString(
|
||||
R.string.accessibility_screen_magnification_title);
|
||||
final String description = getContext().getString(
|
||||
R.string.accessibility_preference_magnification_summary);
|
||||
final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
|
||||
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
|
||||
description, icon);
|
||||
|
||||
// Hide the setting from the vision settings.
|
||||
mSettingsPreference.setVisible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
|
||||
Bundle savedInstanceState) {
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
|
||||
return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION;
|
||||
@@ -49,12 +82,4 @@ public class ToggleScreenMagnificationPreferenceFragmentForSetupWizard
|
||||
// Hides help center in action bar and footer bar in SuW
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// Hide the setting from the vision settings.
|
||||
mSettingsPreference.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
@@ -17,8 +17,17 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
|
||||
public class ToggleScreenReaderPreferenceFragmentForSetupWizard
|
||||
extends ToggleAccessibilityServicePreferenceFragment {
|
||||
@@ -28,9 +37,24 @@ public class ToggleScreenReaderPreferenceFragmentForSetupWizard
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
|
||||
final String title = getArguments().getString(AccessibilitySettings.EXTRA_TITLE);
|
||||
final String description = getContext().getString(R.string.talkback_summary);
|
||||
final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
|
||||
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
|
||||
description, icon);
|
||||
|
||||
mToggleSwitchWasInitiallyChecked = mToggleServiceSwitchPreference.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
|
||||
Bundle savedInstanceState) {
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
|
||||
return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER;
|
||||
|
@@ -17,8 +17,17 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
|
||||
public class ToggleSelectToSpeakPreferenceFragmentForSetupWizard
|
||||
extends InvisibleToggleAccessibilityServicePreferenceFragment {
|
||||
@@ -28,12 +37,27 @@ public class ToggleSelectToSpeakPreferenceFragmentForSetupWizard
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
|
||||
final String title = getArguments().getString(AccessibilitySettings.EXTRA_TITLE);
|
||||
final String description = getContext().getString(R.string.select_to_speak_summary);
|
||||
final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
|
||||
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
|
||||
description, icon);
|
||||
|
||||
mToggleSwitchWasInitiallyChecked = mToggleServiceSwitchPreference.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
|
||||
Bundle savedInstanceState) {
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
|
||||
return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER;
|
||||
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -37,6 +37,7 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
|
||||
import com.android.settings.homepage.SettingsHomepageActivity;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
@@ -105,6 +106,17 @@ public class AvatarViewMixin implements LifecycleObserver {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set a component name since activity embedding requires a component name for
|
||||
// registering a rule.
|
||||
intent.setComponent(matchedIntents.get(0).getComponentInfo().getComponentName());
|
||||
ActivityEmbeddingRulesController.registerTwoPanePairRuleForSettingsHome(
|
||||
mContext,
|
||||
intent.getComponent(),
|
||||
intent.getAction(),
|
||||
false /* finishPrimaryWithSecondary */,
|
||||
true /* finishSecondaryWithPrimary */,
|
||||
false /* clearTop */);
|
||||
|
||||
FeatureFactory.getFactory(mContext).getMetricsFeatureProvider()
|
||||
.logSettingsTileClick(KEY_AVATAR_ICON, SettingsEnums.SETTINGS_HOMEPAGE);
|
||||
|
||||
|
@@ -22,6 +22,7 @@ import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -71,6 +72,11 @@ public class CrossProfileCalendarPreferenceController extends TogglePreferenceCo
|
||||
CROSS_PROFILE_CALENDAR_ENABLED, value, mManagedUser.getIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accounts;
|
||||
}
|
||||
|
||||
static boolean isCrossProfileCalendarDisallowedByAdmin(Context context, int userId) {
|
||||
final Context managedProfileContext = createPackageContextAsUser(context, userId);
|
||||
final DevicePolicyManager dpm = managedProfileContext.getSystemService(
|
||||
|
@@ -16,33 +16,25 @@
|
||||
|
||||
package com.android.settings.accounts;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.Indexable;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Setting page for managed profile.
|
||||
|
@@ -53,6 +53,7 @@ import java.io.IOException;
|
||||
public class RemoveAccountPreferenceController extends AbstractPreferenceController
|
||||
implements PreferenceControllerMixin, OnClickListener {
|
||||
|
||||
private static final String TAG = "RemoveAccountPrefController";
|
||||
private static final String KEY_REMOVE_ACCOUNT = "remove_account";
|
||||
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
@@ -175,10 +176,11 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
|
||||
| IOException
|
||||
| AuthenticatorException e) {
|
||||
// handled below
|
||||
}
|
||||
if (failed) {
|
||||
Log.w(TAG, "Remove account error: " + e);
|
||||
RemoveAccountFailureDialog.show(getTargetFragment());
|
||||
} else {
|
||||
}
|
||||
Log.i(TAG, "failed: " + failed);
|
||||
if (!failed) {
|
||||
targetActivity.finish();
|
||||
}
|
||||
}, null, mUserHandle);
|
||||
@@ -210,7 +212,7 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
|
||||
final Context context = getActivity();
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.really_remove_account_title)
|
||||
.setTitle(R.string.remove_account_label)
|
||||
.setMessage(R.string.remove_account_failed)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create();
|
||||
|
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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.activityembedding;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.LayoutDirection;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.window.embedding.ActivityFilter;
|
||||
import androidx.window.embedding.ActivityRule;
|
||||
import androidx.window.embedding.SplitController;
|
||||
import androidx.window.embedding.SplitPairFilter;
|
||||
import androidx.window.embedding.SplitPairRule;
|
||||
import androidx.window.embedding.SplitPlaceholderRule;
|
||||
import androidx.window.embedding.SplitRule;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
|
||||
import com.android.settings.homepage.DeepLinkHomepageActivity;
|
||||
import com.android.settings.homepage.SettingsHomepageActivity;
|
||||
import com.android.settings.homepage.SliceDeepLinkHomepageActivity;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** A class to initialize split rules for activity embedding. */
|
||||
public class ActivityEmbeddingRulesController {
|
||||
|
||||
private static final String TAG = "ActivityEmbeddingCtrl";
|
||||
private final Context mContext;
|
||||
private final SplitController mSplitController;
|
||||
|
||||
public ActivityEmbeddingRulesController(Context context) {
|
||||
mContext = context;
|
||||
mSplitController = SplitController.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up embedding rules to place activities to the right pane.
|
||||
*/
|
||||
public void initRules() {
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext)) {
|
||||
Log.d(TAG, "Not support this feature now");
|
||||
return;
|
||||
}
|
||||
|
||||
mSplitController.clearRegisteredRules();
|
||||
|
||||
// Set a placeholder for home page.
|
||||
registerHomepagePlaceholderRule();
|
||||
|
||||
registerAlwaysExpandRule();
|
||||
}
|
||||
|
||||
/** Register a SplitPairRule for 2-pane. */
|
||||
public static void registerTwoPanePairRule(Context context,
|
||||
ComponentName primaryComponent,
|
||||
ComponentName secondaryComponent,
|
||||
String secondaryIntentAction,
|
||||
int finishPrimaryWithSecondary,
|
||||
int finishSecondaryWithPrimary,
|
||||
boolean clearTop) {
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
final Set<SplitPairFilter> filters = new HashSet<>();
|
||||
filters.add(new SplitPairFilter(primaryComponent, secondaryComponent,
|
||||
secondaryIntentAction));
|
||||
|
||||
SplitController.getInstance().registerRule(new SplitPairRule(filters,
|
||||
finishPrimaryWithSecondary,
|
||||
finishSecondaryWithPrimary,
|
||||
clearTop,
|
||||
ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(context),
|
||||
ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(context),
|
||||
ActivityEmbeddingUtils.SPLIT_RATIO,
|
||||
LayoutDirection.LOCALE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new SplitPairRule for Settings home. Because homepage is able to be opened by
|
||||
* {@link Settings} or {@link SettingsHomepageActivity} or
|
||||
* {@link SliceDeepLinkHomepageActivity}, we register split rule for above cases.
|
||||
*/
|
||||
public static void registerTwoPanePairRuleForSettingsHome(Context context,
|
||||
ComponentName secondaryComponent,
|
||||
String secondaryIntentAction,
|
||||
boolean finishPrimaryWithSecondary,
|
||||
boolean finishSecondaryWithPrimary,
|
||||
boolean clearTop) {
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerTwoPanePairRule(
|
||||
context,
|
||||
new ComponentName(context, Settings.class),
|
||||
secondaryComponent,
|
||||
secondaryIntentAction,
|
||||
finishPrimaryWithSecondary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
|
||||
finishSecondaryWithPrimary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
|
||||
clearTop);
|
||||
|
||||
registerTwoPanePairRule(
|
||||
context,
|
||||
new ComponentName(context, SettingsHomepageActivity.class),
|
||||
secondaryComponent,
|
||||
secondaryIntentAction,
|
||||
finishPrimaryWithSecondary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
|
||||
finishSecondaryWithPrimary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
|
||||
clearTop);
|
||||
|
||||
// We should finish HomePageActivity altogether even if it shows in single pane for all deep
|
||||
// link cases.
|
||||
registerTwoPanePairRule(
|
||||
context,
|
||||
new ComponentName(context, DeepLinkHomepageActivity.class),
|
||||
secondaryComponent,
|
||||
secondaryIntentAction,
|
||||
finishPrimaryWithSecondary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
|
||||
finishSecondaryWithPrimary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
|
||||
clearTop);
|
||||
|
||||
registerTwoPanePairRule(
|
||||
context,
|
||||
new ComponentName(context, SliceDeepLinkHomepageActivity.class),
|
||||
secondaryComponent,
|
||||
secondaryIntentAction,
|
||||
finishPrimaryWithSecondary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
|
||||
finishSecondaryWithPrimary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
|
||||
clearTop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new SplitPairRule for Settings home.
|
||||
*/
|
||||
public static void registerTwoPanePairRuleForSettingsHome(Context context,
|
||||
ComponentName secondaryComponent,
|
||||
String secondaryIntentAction,
|
||||
boolean clearTop) {
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerTwoPanePairRuleForSettingsHome(
|
||||
context,
|
||||
secondaryComponent,
|
||||
secondaryIntentAction,
|
||||
true /* finishPrimaryWithSecondary */,
|
||||
true /* finishSecondaryWithPrimary */,
|
||||
clearTop);
|
||||
}
|
||||
|
||||
/** Register a SplitPairRule for SubSettings if the device supports 2-pane. */
|
||||
public static void registerSubSettingsPairRule(Context context, boolean clearTop) {
|
||||
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerTwoPanePairRuleForSettingsHome(
|
||||
context,
|
||||
new ComponentName(context, SubSettings.class),
|
||||
null /* secondaryIntentAction */,
|
||||
clearTop);
|
||||
}
|
||||
|
||||
private void registerHomepagePlaceholderRule() {
|
||||
final Set<ActivityFilter> activityFilters = new HashSet<>();
|
||||
addActivityFilter(activityFilters, SettingsHomepageActivity.class);
|
||||
addActivityFilter(activityFilters, DeepLinkHomepageActivity.class);
|
||||
addActivityFilter(activityFilters, SliceDeepLinkHomepageActivity.class);
|
||||
addActivityFilter(activityFilters, Settings.class);
|
||||
|
||||
final Intent intent = new Intent(mContext, Settings.NetworkDashboardActivity.class);
|
||||
final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule(
|
||||
activityFilters,
|
||||
intent,
|
||||
true /* stickyPlaceholder */,
|
||||
SplitRule.FINISH_ADJACENT,
|
||||
ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(mContext),
|
||||
ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(mContext),
|
||||
ActivityEmbeddingUtils.SPLIT_RATIO,
|
||||
LayoutDirection.LOCALE);
|
||||
|
||||
mSplitController.registerRule(placeholderRule);
|
||||
}
|
||||
|
||||
private void registerAlwaysExpandRule() {
|
||||
final Set<ActivityFilter> activityFilters = new HashSet<>();
|
||||
addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class);
|
||||
addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
|
||||
mSplitController.registerRule(new ActivityRule(activityFilters, true /* alwaysExpand */));
|
||||
}
|
||||
|
||||
private void addActivityFilter(Set<ActivityFilter> activityFilters,
|
||||
Class<? extends Activity> activityClass) {
|
||||
activityFilters.add(new ActivityFilter(new ComponentName(mContext, activityClass),
|
||||
null /* intentAction */));
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.activityembedding;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import androidx.window.embedding.SplitController;
|
||||
|
||||
/** An util class collecting all common methods for the embedding activity features. */
|
||||
public class ActivityEmbeddingUtils {
|
||||
public static final float SPLIT_RATIO = 0.5f;
|
||||
// The smallest value of current width of the window when the split should be used.
|
||||
private static final float MIN_CURRENT_SCREEN_SPLIT_WIDTH_DP = 720f;
|
||||
// The smallest value of the smallest-width (sw) of the window in any rotation when
|
||||
// the split should be used.
|
||||
private static final float MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP = 600f;
|
||||
private static final String TAG = "ActivityEmbeddingUtils";
|
||||
|
||||
/** Get the smallest pixel value of width of the window when the split should be used. */
|
||||
public static int getMinCurrentScreenSplitWidthPx(Context context) {
|
||||
final DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
return (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, MIN_CURRENT_SCREEN_SPLIT_WIDTH_DP, dm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the smallest pixel value of the smallest-width (sw) of the window in any rotation when
|
||||
* the split should be used.
|
||||
*/
|
||||
public static int getMinSmallestScreenSplitWidthPx(Context context) {
|
||||
final DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
return (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP, dm);
|
||||
}
|
||||
|
||||
/** Whether to support embedding activity feature. */
|
||||
public static boolean isEmbeddingActivityEnabled(Context context) {
|
||||
final boolean isFlagEnabled = FeatureFlagUtils.isEnabled(context,
|
||||
FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN);
|
||||
final boolean isSplitSupported = SplitController.getInstance().isSplitSupported();
|
||||
|
||||
Log.d(TAG, "isFlagEnabled = " + isFlagEnabled);
|
||||
Log.d(TAG, "isSplitSupported = " + isSplitSupported);
|
||||
|
||||
return isFlagEnabled && isSplitSupported;
|
||||
}
|
||||
|
||||
/** Whether the screen meets two-pane resolution. */
|
||||
public static boolean isTwoPaneResolution(Activity activity) {
|
||||
final Rect currentTaskBounds =
|
||||
ActivityTaskManager.getInstance().getTaskBounds(activity.getTaskId());
|
||||
|
||||
return currentTaskBounds.width() >= getMinCurrentScreenSplitWidthPx(activity)
|
||||
&& currentTaskBounds.height() >= getMinSmallestScreenSplitWidthPx(activity);
|
||||
}
|
||||
}
|
@@ -26,6 +26,7 @@ import static com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED;
|
||||
import static com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.apphibernation.AppHibernationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.DeviceConfig;
|
||||
@@ -134,8 +135,15 @@ public final class HibernationSwitchPreferenceController extends AppInfoPreferen
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object isChecked) {
|
||||
try {
|
||||
final boolean checked = (boolean) isChecked;
|
||||
mAppOpsManager.setUidMode(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, mPackageUid,
|
||||
(boolean) isChecked ? MODE_ALLOWED : MODE_IGNORED);
|
||||
checked ? MODE_ALLOWED : MODE_IGNORED);
|
||||
if (!checked) {
|
||||
final AppHibernationManager ahm =
|
||||
mContext.getSystemService(AppHibernationManager.class);
|
||||
ahm.setHibernatingForUser(mPackageName, false);
|
||||
ahm.setHibernatingGlobally(mPackageName, false);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.applications.autofill;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.service.autofill.AutofillService.EXTRA_RESULT;
|
||||
|
||||
import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
|
||||
@@ -133,7 +134,8 @@ public class PasswordsPreferenceController extends BasePreferenceController
|
||||
new Intent(Intent.ACTION_MAIN)
|
||||
.setClassName(
|
||||
serviceInfo.packageName,
|
||||
service.getPasswordsActivity());
|
||||
service.getPasswordsActivity())
|
||||
.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
prefContext.startActivityAsUser(intent, UserHandle.of(user));
|
||||
return true;
|
||||
});
|
||||
|
@@ -105,6 +105,11 @@ public class AppLaunchSettings extends AppInfoBase implements
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (mAppEntry == null) {
|
||||
Log.w(TAG, "onCreate: mAppEntry is null, please check the reason!!!");
|
||||
getActivity().finish();
|
||||
return;
|
||||
}
|
||||
addPreferencesFromResource(R.xml.installed_app_launch_settings);
|
||||
mDomainVerificationManager = mContext.getSystemService(DomainVerificationManager.class);
|
||||
initUIComponents();
|
||||
|
@@ -272,8 +272,8 @@ public class ManageApplications extends InstrumentedFragment
|
||||
|
||||
Intent intent = activity.getIntent();
|
||||
Bundle args = getArguments();
|
||||
int screenTitle = intent.getIntExtra(
|
||||
SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.all_apps);
|
||||
final int screenTitle = getTitleResId(intent, args);
|
||||
|
||||
String className = args != null ? args.getString(EXTRA_CLASSNAME) : null;
|
||||
if (className == null) {
|
||||
className = intent.getComponent().getClassName();
|
||||
@@ -290,49 +290,36 @@ public class ManageApplications extends InstrumentedFragment
|
||||
mSortOrder = R.id.sort_order_size;
|
||||
} else if (className.equals(UsageAccessSettingsActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_USAGE_ACCESS;
|
||||
screenTitle = R.string.usage_access;
|
||||
} else if (className.equals(HighPowerApplicationsActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_HIGH_POWER;
|
||||
// Default to showing system.
|
||||
mShowSystem = true;
|
||||
screenTitle = R.string.high_power_apps;
|
||||
} else if (className.equals(OverlaySettingsActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_OVERLAY;
|
||||
screenTitle = R.string.system_alert_window_settings;
|
||||
|
||||
reportIfRestrictedSawIntent(intent);
|
||||
} else if (className.equals(WriteSettingsActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_WRITE_SETTINGS;
|
||||
screenTitle = R.string.write_settings;
|
||||
} else if (className.equals(ManageExternalSourcesActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_MANAGE_SOURCES;
|
||||
screenTitle = R.string.install_other_apps;
|
||||
} else if (className.equals(GamesStorageActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_GAMES;
|
||||
mSortOrder = R.id.sort_order_size;
|
||||
} else if (className.equals(Settings.ChangeWifiStateActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_WIFI_ACCESS;
|
||||
screenTitle = R.string.change_wifi_state_title;
|
||||
} else if (className.equals(Settings.ManageExternalStorageActivity.class.getName())) {
|
||||
mListType = LIST_MANAGE_EXTERNAL_STORAGE;
|
||||
screenTitle = R.string.manage_external_storage_title;
|
||||
} else if (className.equals(Settings.MediaManagementAppsActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_MEDIA_MANAGEMENT_APPS;
|
||||
screenTitle = R.string.media_management_apps_title;
|
||||
} else if (className.equals(Settings.AlarmsAndRemindersActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_ALARMS_AND_REMINDERS;
|
||||
screenTitle = R.string.alarms_and_reminders_title;
|
||||
} else if (className.equals(Settings.NotificationAppListActivity.class.getName())) {
|
||||
mListType = LIST_TYPE_NOTIFICATION;
|
||||
mUsageStatsManager = IUsageStatsManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.USAGE_STATS_SERVICE));
|
||||
mNotificationBackend = new NotificationBackend();
|
||||
mSortOrder = R.id.sort_order_recent_notification;
|
||||
screenTitle = R.string.app_notifications_title;
|
||||
} else {
|
||||
if (screenTitle == -1) {
|
||||
screenTitle = R.string.all_apps;
|
||||
}
|
||||
mListType = LIST_TYPE_MAIN;
|
||||
}
|
||||
final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();
|
||||
@@ -881,6 +868,46 @@ public class ManageApplications extends InstrumentedFragment
|
||||
params.setBehavior(behavior);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a resource ID of title based on what type of app list is
|
||||
* @param intent the intent of the activity that might include a specified title
|
||||
* @param args the args that includes a class name of app list
|
||||
*/
|
||||
public static int getTitleResId(@NonNull Intent intent, Bundle args) {
|
||||
int screenTitle = intent.getIntExtra(
|
||||
SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.all_apps);
|
||||
String className = args != null ? args.getString(EXTRA_CLASSNAME) : null;
|
||||
if (className == null) {
|
||||
className = intent.getComponent().getClassName();
|
||||
}
|
||||
if (className.equals(Settings.UsageAccessSettingsActivity.class.getName())) {
|
||||
screenTitle = R.string.usage_access;
|
||||
} else if (className.equals(Settings.HighPowerApplicationsActivity.class.getName())) {
|
||||
screenTitle = R.string.high_power_apps;
|
||||
} else if (className.equals(Settings.OverlaySettingsActivity.class.getName())) {
|
||||
screenTitle = R.string.system_alert_window_settings;
|
||||
} else if (className.equals(Settings.WriteSettingsActivity.class.getName())) {
|
||||
screenTitle = R.string.write_settings;
|
||||
} else if (className.equals(Settings.ManageExternalSourcesActivity.class.getName())) {
|
||||
screenTitle = R.string.install_other_apps;
|
||||
} else if (className.equals(Settings.ChangeWifiStateActivity.class.getName())) {
|
||||
screenTitle = R.string.change_wifi_state_title;
|
||||
} else if (className.equals(Settings.ManageExternalStorageActivity.class.getName())) {
|
||||
screenTitle = R.string.manage_external_storage_title;
|
||||
} else if (className.equals(Settings.MediaManagementAppsActivity.class.getName())) {
|
||||
screenTitle = R.string.media_management_apps_title;
|
||||
} else if (className.equals(Settings.AlarmsAndRemindersActivity.class.getName())) {
|
||||
screenTitle = R.string.alarms_and_reminders_title;
|
||||
} else if (className.equals(Settings.NotificationAppListActivity.class.getName())) {
|
||||
screenTitle = R.string.app_notifications_title;
|
||||
} else {
|
||||
if (screenTitle == -1) {
|
||||
screenTitle = R.string.all_apps;
|
||||
}
|
||||
}
|
||||
return screenTitle;
|
||||
}
|
||||
|
||||
static class FilterSpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> {
|
||||
|
||||
private final ManageApplications mManageApplications;
|
||||
|
@@ -17,27 +17,26 @@
|
||||
package com.android.settings.applications.managedomainurls;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
import android.content.pm.verify.domain.DomainVerificationManager;
|
||||
import android.content.pm.verify.domain.DomainVerificationUserState;
|
||||
import android.util.IconDrawableFactory;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.applications.intentpicker.IntentPickerUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
import com.android.settingslib.widget.AppPreference;
|
||||
|
||||
public class DomainAppPreference extends AppPreference {
|
||||
|
||||
private final AppEntry mEntry;
|
||||
private final PackageManager mPm;
|
||||
private final DomainVerificationManager mDomainVerificationManager;
|
||||
private final IconDrawableFactory mIconDrawableFactory;
|
||||
|
||||
public DomainAppPreference(final Context context, IconDrawableFactory iconFactory,
|
||||
AppEntry entry) {
|
||||
super(context);
|
||||
mIconDrawableFactory = iconFactory;
|
||||
mPm = context.getPackageManager();
|
||||
mDomainVerificationManager = context.getSystemService(DomainVerificationManager.class);
|
||||
mEntry = entry;
|
||||
mEntry.ensureLabel(getContext());
|
||||
|
||||
@@ -60,22 +59,14 @@ public class DomainAppPreference extends AppPreference {
|
||||
}
|
||||
|
||||
private CharSequence getDomainsSummary(String packageName) {
|
||||
// If the user has explicitly said "no" for this package, that's the
|
||||
// string we should show.
|
||||
int domainStatus =
|
||||
mPm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId());
|
||||
if (domainStatus == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
|
||||
return getContext().getText(R.string.domain_urls_summary_none);
|
||||
}
|
||||
// Otherwise, ask package manager for the domains for this package,
|
||||
// and show the first one (or none if there aren't any).
|
||||
final ArraySet<String> result = Utils.getHandledDomains(mPm, packageName);
|
||||
if (result.isEmpty()) {
|
||||
return getContext().getText(R.string.domain_urls_summary_none);
|
||||
} else if (result.size() == 1) {
|
||||
return getContext().getString(R.string.domain_urls_summary_one, result.valueAt(0));
|
||||
} else {
|
||||
return getContext().getString(R.string.domain_urls_summary_some, result.valueAt(0));
|
||||
}
|
||||
return getContext().getText(isLinkHandlingAllowed(packageName)
|
||||
? R.string.app_link_open_always : R.string.app_link_open_never);
|
||||
}
|
||||
|
||||
private boolean isLinkHandlingAllowed(String packageName) {
|
||||
final DomainVerificationUserState userState =
|
||||
IntentPickerUtils.getDomainVerificationUserState(mDomainVerificationManager,
|
||||
packageName);
|
||||
return userState == null ? false : userState.isLinkHandlingAllowed();
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ package com.android.settings.applications.managedomainurls;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class InstantAppWebActionPreferenceController extends TogglePreferenceController {
|
||||
@@ -43,4 +44,9 @@ public class InstantAppWebActionPreferenceController extends TogglePreferenceCon
|
||||
return Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.INSTANT_APPS_ENABLED, isChecked ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_apps;
|
||||
}
|
||||
}
|
||||
|
@@ -67,7 +67,9 @@ public class PictureInPictureDetailPreferenceController extends AppInfoPreferenc
|
||||
try {
|
||||
packageInfoWithActivities = mPackageManager.getPackageInfoAsUser(mPackageName,
|
||||
PackageManager.GET_ACTIVITIES, UserHandle.myUserId());
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
} catch (Exception e) {
|
||||
// Catch Exception to avoid DeadObjectException thrown with binder transaction
|
||||
// failures, since the explicit request of DeadObjectException has compiler errors.
|
||||
Log.e(TAG, "Exception while retrieving the package info of " + mPackageName, e);
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@ import android.util.Log;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class AutoRestorePreferenceController extends TogglePreferenceController {
|
||||
@@ -84,4 +85,9 @@ public class AutoRestorePreferenceController extends TogglePreferenceController
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_system;
|
||||
}
|
||||
}
|
@@ -22,6 +22,7 @@ import android.app.backup.BackupDataOutput;
|
||||
import android.app.backup.BackupHelper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import com.android.settings.fuelgauge.BatteryBackupHelper;
|
||||
import com.android.settings.shortcut.CreateShortcutPreferenceController;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
@@ -37,6 +38,7 @@ public class SettingsBackupHelper extends BackupAgentHelper {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
addHelper("no-op", new NoOpHelper());
|
||||
addHelper(BatteryBackupHelper.TAG, new BatteryBackupHelper(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -32,6 +32,7 @@ import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.biometrics.BiometricManager;
|
||||
import android.hardware.biometrics.BiometricManager.Authenticators;
|
||||
import android.hardware.biometrics.BiometricManager.BiometricError;
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
@@ -175,39 +176,64 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
||||
mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||
|
||||
// Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL.
|
||||
final int authenticators = getIntent().getIntExtra(
|
||||
EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
|
||||
Log.d(TAG, "Authenticators: " + authenticators);
|
||||
|
||||
mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false);
|
||||
mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false);
|
||||
|
||||
// determine what can be enrolled
|
||||
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
final boolean isMultiSensor = mHasFeatureFace && mHasFeatureFingerprint;
|
||||
|
||||
Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired
|
||||
+ ", skipReturnToParent: " + mSkipReturnToParent
|
||||
+ ", isSetupWizard: " + isSetupWizard
|
||||
+ ", isMultiSensor: " + isMultiSensor);
|
||||
|
||||
if (mHasFeatureFace) {
|
||||
final FaceManager faceManager = getSystemService(FaceManager.class);
|
||||
final List<FaceSensorPropertiesInternal> faceProperties =
|
||||
faceManager.getSensorPropertiesInternal();
|
||||
final int maxFacesEnrollableIfSUW = getApplicationContext().getResources()
|
||||
.getInteger(R.integer.suw_max_faces_enrollable);
|
||||
if (!faceProperties.isEmpty()) {
|
||||
final FaceSensorPropertiesInternal props = faceProperties.get(0);
|
||||
final int maxEnrolls =
|
||||
isSetupWizard ? 1 : faceProperties.get(0).maxEnrollmentsPerUser;
|
||||
isSetupWizard ? maxFacesEnrollableIfSUW : props.maxEnrollmentsPerUser;
|
||||
mIsFaceEnrollable =
|
||||
faceManager.getEnrolledFaces(mUserId).size() < maxEnrolls;
|
||||
|
||||
// exclude face enrollment from setup wizard if configured as a convenience
|
||||
// isSetupWizard is always false for unicorn enrollment, so if consent is
|
||||
// required check if setup has completed instead.
|
||||
final boolean isSettingUp = isSetupWizard || (mParentalOptionsRequired
|
||||
&& !WizardManagerHelper.isUserSetupComplete(this));
|
||||
if (isSettingUp && isMultiSensor && mIsFaceEnrollable) {
|
||||
if (props.sensorStrength == SensorProperties.STRENGTH_CONVENIENCE) {
|
||||
Log.i(TAG, "Excluding face from SuW enrollment (STRENGTH_CONVENIENCE)");
|
||||
mIsFaceEnrollable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mHasFeatureFingerprint) {
|
||||
final FingerprintManager fpManager = getSystemService(FingerprintManager.class);
|
||||
final List<FingerprintSensorPropertiesInternal> fpProperties =
|
||||
fpManager.getSensorPropertiesInternal();
|
||||
final int maxFingerprintsEnrollableIfSUW = getApplicationContext().getResources()
|
||||
.getInteger(R.integer.suw_max_fingerprints_enrollable);
|
||||
if (!fpProperties.isEmpty()) {
|
||||
final int maxEnrolls =
|
||||
isSetupWizard ? 1 : fpProperties.get(0).maxEnrollmentsPerUser;
|
||||
isSetupWizard ? maxFingerprintsEnrollableIfSUW
|
||||
: fpProperties.get(0).maxEnrollmentsPerUser;
|
||||
mIsFingerprintEnrollable =
|
||||
fpManager.getEnrolledFingerprints(mUserId).size() < maxEnrolls;
|
||||
}
|
||||
}
|
||||
|
||||
mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false);
|
||||
mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false);
|
||||
|
||||
Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired
|
||||
+ ", skipReturnToParent: " + mSkipReturnToParent
|
||||
+ ", isSetupWizard: " + isSetupWizard);
|
||||
|
||||
// TODO(b/195128094): remove this restriction
|
||||
// Consent can only be recorded when this activity is launched directly from the kids
|
||||
// module. This can be removed when there is a way to notify consent status out of band.
|
||||
@@ -236,28 +262,21 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
}
|
||||
}
|
||||
|
||||
// start enrollment process if we haven't bailed out yet
|
||||
if (mParentalOptionsRequired && mParentalOptions == null) {
|
||||
mParentalConsentHelper = new ParentalConsentHelper(
|
||||
mIsFaceEnrollable, mIsFingerprintEnrollable, mGkPwHandle);
|
||||
mParentalConsentHelper = new ParentalConsentHelper(mGkPwHandle);
|
||||
setOrConfirmCredentialsNow();
|
||||
} else {
|
||||
startEnroll();
|
||||
// Start enrollment process if we haven't bailed out yet
|
||||
startEnrollWith(authenticators, isSetupWizard);
|
||||
}
|
||||
}
|
||||
|
||||
private void startEnroll() {
|
||||
// Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL.
|
||||
final int authenticators = getIntent().getIntExtra(
|
||||
EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
|
||||
Log.d(TAG, "Authenticators: " + authenticators);
|
||||
|
||||
startEnrollWith(authenticators, WizardManagerHelper.isAnySetupWizard(getIntent()));
|
||||
}
|
||||
|
||||
private void startEnrollWith(@Authenticators.Types int authenticators, boolean setupWizard) {
|
||||
// If the caller is not setup wizard, and the user has something enrolled, finish.
|
||||
if (!setupWizard) {
|
||||
// Allow parental consent flow to skip this check, since one modality could be consented
|
||||
// and another non-consented. This can also happen if the restriction is applied when
|
||||
// enrollments already exists.
|
||||
if (!setupWizard && !mParentalOptionsRequired) {
|
||||
final BiometricManager bm = getSystemService(BiometricManager.class);
|
||||
final @BiometricError int result = bm.canAuthenticate(authenticators);
|
||||
if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
|
||||
@@ -324,6 +343,27 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
// single enrollment is handled entirely by the launched activity
|
||||
// this handles multi enroll or if parental consent is required
|
||||
if (mParentalConsentHelper != null) {
|
||||
// Lazily retrieve the values from ParentalControlUtils, since the value may not be
|
||||
// ready in onCreate.
|
||||
final boolean faceConsentRequired = ParentalControlsUtils
|
||||
.parentConsentRequired(this, BiometricAuthenticator.TYPE_FACE) != null;
|
||||
final boolean fpConsentRequired = ParentalControlsUtils
|
||||
.parentConsentRequired(this, BiometricAuthenticator.TYPE_FINGERPRINT) != null;
|
||||
|
||||
final boolean requestFaceConsent = faceConsentRequired
|
||||
&& mHasFeatureFace
|
||||
&& mIsFaceEnrollable;
|
||||
final boolean requestFpConsent = fpConsentRequired && mHasFeatureFingerprint;
|
||||
|
||||
Log.d(TAG, "faceConsentRequired: " + faceConsentRequired
|
||||
+ ", fpConsentRequired: " + fpConsentRequired
|
||||
+ ", hasFeatureFace: " + mHasFeatureFace
|
||||
+ ", hasFeatureFingerprint: " + mHasFeatureFingerprint
|
||||
+ ", faceEnrollable: " + mIsFaceEnrollable
|
||||
+ ", fpEnrollable: " + mIsFingerprintEnrollable);
|
||||
|
||||
mParentalConsentHelper.setConsentRequirement(requestFaceConsent, requestFpConsent);
|
||||
|
||||
handleOnActivityResultWhileConsenting(requestCode, resultCode, data);
|
||||
} else {
|
||||
handleOnActivityResultWhileEnrolling(requestCode, resultCode, data);
|
||||
@@ -356,10 +396,18 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
final boolean isStillPrompting = mParentalConsentHelper.launchNext(
|
||||
this, REQUEST_CHOOSE_OPTIONS, resultCode, data);
|
||||
if (!isStillPrompting) {
|
||||
Log.d(TAG, "Enrollment consent options set, starting enrollment");
|
||||
mParentalOptions = mParentalConsentHelper.getConsentResult();
|
||||
mParentalConsentHelper = null;
|
||||
startEnroll();
|
||||
Log.d(TAG, "Enrollment consent options set, starting enrollment: "
|
||||
+ mParentalOptions);
|
||||
// Note that we start enrollment with CONVENIENCE instead of the default
|
||||
// of WEAK in startEnroll(), since we want to allow enrollment for any
|
||||
// sensor as long as it has been consented for. We should eventually
|
||||
// clean up this logic and do something like pass in the parental consent
|
||||
// result, so that we can request enrollment for specific sensors, but
|
||||
// that's quite a large and risky change to the startEnrollWith() logic.
|
||||
startEnrollWith(Authenticators.BIOMETRIC_CONVENIENCE,
|
||||
WizardManagerHelper.isAnySetupWizard(getIntent()));
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Unknown or cancelled parental consent");
|
||||
|
@@ -203,11 +203,15 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
getMoreButtonTextRes(), this::onNextButtonClick);
|
||||
requireScrollMixin.setOnRequireScrollStateChangedListener(
|
||||
scrollNeeded -> {
|
||||
// Update text of primary button from "More" to "Agree".
|
||||
final int primaryButtonTextRes = scrollNeeded
|
||||
? getMoreButtonTextRes()
|
||||
: getAgreeButtonTextRes();
|
||||
getPrimaryFooterButton().setText(this, primaryButtonTextRes);
|
||||
|
||||
boolean enrollmentCompleted = checkMaxEnrolled() != 0;
|
||||
if (!enrollmentCompleted) {
|
||||
// Update text of primary button from "More" to "Agree".
|
||||
final int primaryButtonTextRes = scrollNeeded
|
||||
? getMoreButtonTextRes()
|
||||
: getAgreeButtonTextRes();
|
||||
getPrimaryFooterButton().setText(this, primaryButtonTextRes);
|
||||
}
|
||||
|
||||
// Show secondary button once scroll is completed.
|
||||
if (!scrollNeeded) {
|
||||
@@ -257,8 +261,12 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
// Lock thingy is already set up, launch directly to the next page
|
||||
launchNextEnrollingActivity(mToken);
|
||||
} else {
|
||||
setResult(RESULT_FINISHED);
|
||||
finish();
|
||||
boolean couldStartNextBiometric = BiometricUtils.tryStartingNextBiometricEnroll(this,
|
||||
ENROLL_NEXT_BIOMETRIC_REQUEST, "enrollIntroduction#onNextButtonClicked");
|
||||
if (!couldStartNextBiometric) {
|
||||
setResult(RESULT_FINISHED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,9 @@ import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
@@ -273,4 +276,17 @@ public class BiometricUtils {
|
||||
public static boolean isReverseLandscape(@NonNull Context context) {
|
||||
return context.getDisplay().getRotation() == Surface.ROTATION_270;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param faceManager
|
||||
* @return True if at least one sensor is set as a convenience.
|
||||
*/
|
||||
public static boolean isConvenience(@NonNull FaceManager faceManager) {
|
||||
for (FaceSensorPropertiesInternal props : faceManager.getSensorPropertiesInternal()) {
|
||||
if (props.sensorStrength == SensorProperties.STRENGTH_CONVENIENCE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -52,8 +52,8 @@ public class ParentalConsentHelper {
|
||||
private static final String KEY_FINGERPRINT_CONSENT_STRINGS = "fingerprint_strings";
|
||||
private static final String KEY_IRIS_CONSENT_STRINGS = "iris_strings";
|
||||
|
||||
private final boolean mRequireFace;
|
||||
private final boolean mRequireFingerprint;
|
||||
private boolean mRequireFace;
|
||||
private boolean mRequireFingerprint;
|
||||
|
||||
private long mGkPwHandle;
|
||||
@Nullable
|
||||
@@ -64,15 +64,19 @@ public class ParentalConsentHelper {
|
||||
/**
|
||||
* Helper for aggregating user consent.
|
||||
*
|
||||
* @param requireFace if face consent should be shown
|
||||
* @param requireFingerprint if fingerprint consent should be shown
|
||||
* @param gkPwHandle for launched intents
|
||||
*/
|
||||
public ParentalConsentHelper(boolean requireFace, boolean requireFingerprint,
|
||||
@Nullable Long gkPwHandle) {
|
||||
public ParentalConsentHelper(@Nullable Long gkPwHandle) {
|
||||
mGkPwHandle = gkPwHandle != null ? gkPwHandle : 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requireFace if face consent should be shown
|
||||
* @param requireFingerprint if fingerprint consent should be shown
|
||||
*/
|
||||
public void setConsentRequirement(boolean requireFace, boolean requireFingerprint) {
|
||||
mRequireFace = requireFace;
|
||||
mRequireFingerprint = requireFingerprint;
|
||||
mGkPwHandle = gkPwHandle != null ? gkPwHandle : 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -91,4 +91,10 @@ public class BiometricSettingsAppPreferenceController extends TogglePreferenceCo
|
||||
public final boolean isSliceable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
// not needed since it's not sliceable
|
||||
return NO_RES;
|
||||
}
|
||||
}
|
||||
|
@@ -73,4 +73,10 @@ public class BiometricSettingsKeyguardPreferenceController extends TogglePrefere
|
||||
public final boolean isSliceable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
// not needed since it's not sliceable
|
||||
return NO_RES;
|
||||
}
|
||||
}
|
||||
|
@@ -21,13 +21,18 @@ import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -90,6 +95,16 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
|
||||
mConfirmCredential = true;
|
||||
launchChooseOrConfirmLock();
|
||||
}
|
||||
|
||||
final Preference unlockPhonePreference = findPreference(getUnlockPhonePreferenceKey());
|
||||
if (unlockPhonePreference != null) {
|
||||
unlockPhonePreference.setSummary(getUseAnyBiometricSummary());
|
||||
}
|
||||
|
||||
final Preference useInAppsPreference = findPreference(getUseInAppsPreferenceKey());
|
||||
if (useInAppsPreference != null) {
|
||||
useInAppsPreference.setSummary(getUseClass2BiometricSummary());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,6 +200,16 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
|
||||
*/
|
||||
public abstract String getFingerprintPreferenceKey();
|
||||
|
||||
/**
|
||||
* @return The preference key of the "Unlock your phone" setting toggle.
|
||||
*/
|
||||
public abstract String getUnlockPhonePreferenceKey();
|
||||
|
||||
/**
|
||||
* @return The preference key of the "Verify it's you in apps" setting toggle.
|
||||
*/
|
||||
public abstract String getUseInAppsPreferenceKey();
|
||||
|
||||
private void launchChooseOrConfirmLock() {
|
||||
final ChooseLockSettingsHelper.Builder builder =
|
||||
new ChooseLockSettingsHelper.Builder(getActivity(), this)
|
||||
@@ -214,4 +239,59 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
|
||||
startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String getUseAnyBiometricSummary() {
|
||||
boolean isFaceAllowed = mFaceManager != null && mFaceManager.isHardwareDetected();
|
||||
boolean isFingerprintAllowed =
|
||||
mFingerprintManager != null && mFingerprintManager.isHardwareDetected();
|
||||
|
||||
@StringRes final int resId = getUseBiometricSummaryRes(isFaceAllowed, isFingerprintAllowed);
|
||||
return resId == 0 ? "" : getString(resId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String getUseClass2BiometricSummary() {
|
||||
boolean isFaceAllowed = false;
|
||||
if (mFaceManager != null) {
|
||||
for (final FaceSensorPropertiesInternal sensorProps
|
||||
: mFaceManager.getSensorPropertiesInternal()) {
|
||||
if (sensorProps.sensorStrength == SensorProperties.STRENGTH_WEAK
|
||||
|| sensorProps.sensorStrength == SensorProperties.STRENGTH_STRONG) {
|
||||
isFaceAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isFingerprintAllowed = false;
|
||||
if (mFingerprintManager != null) {
|
||||
for (final FingerprintSensorPropertiesInternal sensorProps
|
||||
: mFingerprintManager.getSensorPropertiesInternal()) {
|
||||
if (sensorProps.sensorStrength == SensorProperties.STRENGTH_WEAK
|
||||
|| sensorProps.sensorStrength == SensorProperties.STRENGTH_STRONG) {
|
||||
isFingerprintAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes final int resId = getUseBiometricSummaryRes(isFaceAllowed, isFingerprintAllowed);
|
||||
return resId == 0 ? "" : getString(resId);
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private static int getUseBiometricSummaryRes(boolean isFaceAllowed,
|
||||
boolean isFingerprintAllowed) {
|
||||
|
||||
if (isFaceAllowed && isFingerprintAllowed) {
|
||||
return R.string.biometric_settings_use_face_or_fingerprint_preference_summary;
|
||||
} else if (isFaceAllowed) {
|
||||
return R.string.biometric_settings_use_face_preference_summary;
|
||||
} else if (isFingerprintAllowed) {
|
||||
return R.string.biometric_settings_use_fingerprint_preference_summary;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@ public class CombinedBiometricProfileSettings extends BiometricsSettingsBase {
|
||||
private static final String TAG = "BiometricProfileSetting";
|
||||
private static final String KEY_FACE_SETTINGS = "biometric_face_settings_profile";
|
||||
private static final String KEY_FINGERPRINT_SETTINGS = "biometric_fingerprint_settings_profile";
|
||||
private static final String KEY_UNLOCK_PHONE = "biometric_settings_biometric_keyguard_profile";
|
||||
private static final String KEY_USE_IN_APPS = "biometric_settings_biometric_app_profile";
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
@@ -50,6 +52,16 @@ public class CombinedBiometricProfileSettings extends BiometricsSettingsBase {
|
||||
return KEY_FINGERPRINT_SETTINGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUnlockPhonePreferenceKey() {
|
||||
return KEY_UNLOCK_PHONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUseInAppsPreferenceKey() {
|
||||
return KEY_USE_IN_APPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
|
@@ -30,6 +30,8 @@ public class CombinedBiometricSettings extends BiometricsSettingsBase {
|
||||
private static final String TAG = "BiometricSettings";
|
||||
private static final String KEY_FACE_SETTINGS = "biometric_face_settings";
|
||||
private static final String KEY_FINGERPRINT_SETTINGS = "biometric_fingerprint_settings";
|
||||
private static final String KEY_UNLOCK_PHONE = "biometric_settings_biometric_keyguard";
|
||||
private static final String KEY_USE_IN_APPS = "biometric_settings_biometric_app";
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
@@ -53,6 +55,16 @@ public class CombinedBiometricSettings extends BiometricsSettingsBase {
|
||||
return KEY_FINGERPRINT_SETTINGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUnlockPhonePreferenceKey() {
|
||||
return KEY_UNLOCK_PHONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUseInAppsPreferenceKey() {
|
||||
return KEY_USE_IN_APPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
|
@@ -104,12 +104,34 @@ public class CombinedBiometricStatusPreferenceController extends
|
||||
private void updateStateInternal() {
|
||||
// This controller currently is shown if fingerprint&face exist on the device. If this
|
||||
// changes in the future, the modalities passed into the below will need to be updated.
|
||||
updateStateInternal(ParentalControlsUtils.parentConsentRequired(mContext,
|
||||
BiometricAuthenticator.TYPE_FACE | BiometricAuthenticator.TYPE_FINGERPRINT));
|
||||
|
||||
final RestrictedLockUtils.EnforcedAdmin faceAdmin = ParentalControlsUtils
|
||||
.parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FACE);
|
||||
final RestrictedLockUtils.EnforcedAdmin fpAdmin = ParentalControlsUtils
|
||||
.parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FINGERPRINT);
|
||||
|
||||
// If the admins are non-null, they are actually always the same. Just the helper class
|
||||
// we create above always return the admin, instead of a boolean.
|
||||
final boolean faceConsentRequired = faceAdmin != null;
|
||||
final boolean fpConsentRequired = fpAdmin != null;
|
||||
final RestrictedLockUtils.EnforcedAdmin admin = faceAdmin != null ? faceAdmin : fpAdmin;
|
||||
|
||||
updateStateInternal(admin, faceConsentRequired, fpConsentRequired);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateStateInternal(@Nullable RestrictedLockUtils.EnforcedAdmin enforcedAdmin) {
|
||||
void updateStateInternal(@Nullable RestrictedLockUtils.EnforcedAdmin enforcedAdmin,
|
||||
boolean faceConsentRequired, boolean fpConsentRequired) {
|
||||
// Disable the preference (and show the consent flow) only if consent is required for all
|
||||
// modalities. Otherwise, users will not be able to enter and modify settings for modalities
|
||||
// which have already been consented. In any case, the controllers for the modalities which
|
||||
// have not yet been consented will be disabled in the combined page anyway - users can
|
||||
// go through the consent+enrollment flow from there.
|
||||
final boolean disablePreference = faceConsentRequired && fpConsentRequired;
|
||||
if (!disablePreference) {
|
||||
enforcedAdmin = null;
|
||||
}
|
||||
|
||||
if (mPreference != null) {
|
||||
mPreference.setDisabledByAdmin(enforcedAdmin);
|
||||
}
|
||||
|
@@ -19,10 +19,12 @@ package com.android.settings.biometrics.face;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
import android.hardware.SensorPrivacyManager;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -34,10 +36,12 @@ import androidx.annotation.StringRes;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollActivity;
|
||||
import com.android.settings.biometrics.BiometricEnrollIntroduction;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.utils.SensorPrivacyManagerHelper;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
@@ -57,6 +61,7 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
@Nullable private FooterButton mPrimaryFooterButton;
|
||||
@Nullable private FooterButton mSecondaryFooterButton;
|
||||
@Nullable private SensorPrivacyManager mSensorPrivacyManager;
|
||||
|
||||
@Override
|
||||
protected void onCancelButtonClick(View view) {
|
||||
@@ -112,6 +117,14 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
howMessage.setText(getHowMessage());
|
||||
inControlMessage.setText(getInControlMessage());
|
||||
|
||||
// Set up and show the "less secure" info section if necessary.
|
||||
if (getResources().getBoolean(R.bool.config_face_intro_show_less_secure)) {
|
||||
final LinearLayout infoRowLessSecure = findViewById(R.id.info_row_less_secure);
|
||||
final ImageView iconLessSecure = findViewById(R.id.icon_less_secure);
|
||||
infoRowLessSecure.setVisibility(View.VISIBLE);
|
||||
iconLessSecure.getBackground().setColorFilter(getIconColorFilter());
|
||||
}
|
||||
|
||||
// Set up and show the "require eyes" info section if necessary.
|
||||
if (getResources().getBoolean(R.bool.config_face_intro_show_require_eyes)) {
|
||||
final LinearLayout infoRowRequireEyes = findViewById(R.id.info_row_require_eyes);
|
||||
@@ -142,6 +155,14 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mSensorPrivacyManager = getApplicationContext()
|
||||
.getSystemService(SensorPrivacyManager.class);
|
||||
final SensorPrivacyManagerHelper helper = SensorPrivacyManagerHelper
|
||||
.getInstance(getApplicationContext());
|
||||
final boolean cameraPrivacyEnabled = helper
|
||||
.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA, mUserId);
|
||||
Log.v(TAG, "cameraPrivacyEnabled : " + cameraPrivacyEnabled);
|
||||
}
|
||||
|
||||
protected boolean generateChallengeOnCreate() {
|
||||
@@ -226,13 +247,20 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
}
|
||||
|
||||
private boolean maxFacesEnrolled() {
|
||||
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
if (mFaceManager != null) {
|
||||
final List<FaceSensorPropertiesInternal> props =
|
||||
mFaceManager.getSensorPropertiesInternal();
|
||||
// This will need to be updated for devices with multiple face sensors.
|
||||
final int max = props.get(0).maxEnrollmentsPerUser;
|
||||
final int numEnrolledFaces = mFaceManager.getEnrolledFaces(mUserId).size();
|
||||
return numEnrolledFaces >= max;
|
||||
final int maxFacesEnrollableIfSUW = getApplicationContext().getResources()
|
||||
.getInteger(R.integer.suw_max_faces_enrollable);
|
||||
if (isSetupWizard) {
|
||||
return numEnrolledFaces >= maxFacesEnrollableIfSUW;
|
||||
} else {
|
||||
return numEnrolledFaces >= max;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -293,6 +321,28 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
return BiometricAuthenticator.TYPE_FACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNextButtonClick(View view) {
|
||||
final boolean parentelConsentRequired =
|
||||
getIntent()
|
||||
.getBooleanExtra(BiometricEnrollActivity.EXTRA_REQUIRE_PARENTAL_CONSENT, false);
|
||||
final boolean cameraPrivacyEnabled = SensorPrivacyManagerHelper
|
||||
.getInstance(getApplicationContext())
|
||||
.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA, mUserId);
|
||||
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
final boolean isSettingUp = isSetupWizard || (parentelConsentRequired
|
||||
&& !WizardManagerHelper.isUserSetupComplete(this));
|
||||
if (cameraPrivacyEnabled && !isSettingUp) {
|
||||
if (mSensorPrivacyManager == null) {
|
||||
mSensorPrivacyManager = getApplicationContext()
|
||||
.getSystemService(SensorPrivacyManager.class);
|
||||
}
|
||||
mSensorPrivacyManager.showSensorUseDialog(SensorPrivacyManager.Sensors.CAMERA);
|
||||
} else {
|
||||
super.onNextButtonClick(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected FooterButton getPrimaryFooterButton() {
|
||||
|
@@ -19,13 +19,17 @@ package com.android.settings.biometrics.face;
|
||||
import static android.provider.Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorProperties;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.Utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Preference controller giving the user an option to always require confirmation.
|
||||
*/
|
||||
@@ -75,6 +79,14 @@ public class FaceSettingsConfirmPreferenceController extends FaceSettingsPrefere
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
List<FaceSensorProperties> properties = mFaceManager.getSensorProperties();
|
||||
// If a sensor is convenience, it is possible that it becomes weak or strong with
|
||||
// an update. For this reason, the sensor is conditionally unavailable.
|
||||
if (!properties.isEmpty()
|
||||
&& properties.get(0).getSensorStrength() == SensorProperties.STRENGTH_CONVENIENCE) {
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
} else {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -51,4 +51,10 @@ public abstract class FaceSettingsPreferenceController extends TogglePreferenceC
|
||||
public final boolean isSliceable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
// not needed since it's not sliceable
|
||||
return NO_RES;
|
||||
}
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@ import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
@@ -56,6 +57,7 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
||||
|
||||
public static class ConfirmRemoveDialog extends InstrumentedDialogFragment {
|
||||
|
||||
private boolean mIsConvenience;
|
||||
private DialogInterface.OnClickListener mOnClickListener;
|
||||
|
||||
@Override
|
||||
@@ -68,7 +70,9 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
builder.setTitle(R.string.security_settings_face_settings_remove_dialog_title)
|
||||
.setMessage(R.string.security_settings_face_settings_remove_dialog_details)
|
||||
.setMessage(mIsConvenience
|
||||
? R.string.security_settings_face_settings_remove_dialog_details_convenience
|
||||
: R.string.security_settings_face_settings_remove_dialog_details)
|
||||
.setPositiveButton(R.string.delete, mOnClickListener)
|
||||
.setNegativeButton(R.string.cancel, mOnClickListener);
|
||||
AlertDialog dialog = builder.create();
|
||||
@@ -76,6 +80,10 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void setIsConvenience(boolean isConvenience) {
|
||||
mIsConvenience = isConvenience;
|
||||
}
|
||||
|
||||
public void setOnClickListener(DialogInterface.OnClickListener listener) {
|
||||
mOnClickListener = listener;
|
||||
}
|
||||
@@ -197,6 +205,7 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
||||
mRemoving = true;
|
||||
ConfirmRemoveDialog dialog = new ConfirmRemoveDialog();
|
||||
dialog.setOnClickListener(mOnClickListener);
|
||||
dialog.setIsConvenience(BiometricUtils.isConvenience(mFaceManager));
|
||||
dialog.show(mActivity.getSupportFragmentManager(), ConfirmRemoveDialog.class.getName());
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package com.android.settings.biometrics.fingerprint;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
@@ -46,7 +47,6 @@ import android.view.animation.Interpolator;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -158,7 +158,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
|
||||
mIsSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
if (mCanAssumeUdfps) {
|
||||
updateTitleAndDescriptionForUdfps();
|
||||
updateTitleAndDescription();
|
||||
} else {
|
||||
setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
|
||||
}
|
||||
@@ -567,6 +567,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
|
||||
private final Animator.AnimatorListener mProgressAnimationListener =
|
||||
new Animator.AnimatorListener() {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) { }
|
||||
|
||||
|
@@ -21,7 +21,11 @@ import android.content.Intent;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.os.Bundle;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -32,6 +36,7 @@ import com.android.settings.biometrics.BiometricEnrollSidecar;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
|
||||
@@ -49,6 +54,10 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
private FingerprintEnrollSidecar mSidecar;
|
||||
private boolean mNextClicked;
|
||||
private boolean mCanAssumeUdfps;
|
||||
private boolean mCanAssumeSidefps;
|
||||
|
||||
private OrientationEventListener mOrientationEventListener;
|
||||
private int mPreviousRotation = 0;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -58,6 +67,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
final List<FingerprintSensorPropertiesInternal> props =
|
||||
fingerprintManager.getSensorPropertiesInternal();
|
||||
mCanAssumeUdfps = props != null && props.size() == 1 && props.get(0).isAnyUdfpsType();
|
||||
mCanAssumeSidefps = props != null && props.size() == 1 && props.get(0).isAnySidefpsType();
|
||||
setContentView(getContentView());
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
mFooterBarMixin.setSecondaryButton(
|
||||
@@ -69,6 +79,8 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
.build()
|
||||
);
|
||||
|
||||
listenOrientationEvent();
|
||||
|
||||
if (mCanAssumeUdfps) {
|
||||
setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title);
|
||||
setDescriptionText(R.string.security_settings_udfps_enroll_find_sensor_message);
|
||||
@@ -80,6 +92,35 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build()
|
||||
);
|
||||
|
||||
LottieAnimationView lottieAnimationView = findViewById(R.id.illustration_lottie);
|
||||
AccessibilityManager am = getSystemService(AccessibilityManager.class);
|
||||
if (am.isEnabled()) {
|
||||
lottieAnimationView.setAnimation(R.raw.udfps_edu_a11y_lottie);
|
||||
}
|
||||
|
||||
} else if (mCanAssumeSidefps) {
|
||||
setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
|
||||
setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message);
|
||||
final LottieAnimationView lottieAnimationView = findViewById(R.id.illustration_lottie);
|
||||
final LottieAnimationView lottieAnimationViewPortrait =
|
||||
findViewById(R.id.illustration_lottie_portrait);
|
||||
final int rotation = getApplicationContext().getDisplay().getRotation();
|
||||
switch(rotation) {
|
||||
case Surface.ROTATION_90:
|
||||
lottieAnimationView.setVisibility(View.GONE);
|
||||
lottieAnimationViewPortrait.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
lottieAnimationView.setVisibility(View.GONE);
|
||||
lottieAnimationViewPortrait.setVisibility(View.VISIBLE);
|
||||
lottieAnimationViewPortrait.setRotation(180);
|
||||
break;
|
||||
default:
|
||||
lottieAnimationView.setVisibility(View.VISIBLE);
|
||||
lottieAnimationViewPortrait.setVisibility(View.GONE);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
|
||||
setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message);
|
||||
@@ -110,7 +151,15 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
}
|
||||
|
||||
mAnimation = null;
|
||||
if (!mCanAssumeUdfps) {
|
||||
if (mCanAssumeUdfps) {
|
||||
LottieAnimationView lottieAnimationView = findViewById(R.id.illustration_lottie);
|
||||
lottieAnimationView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onStartButtonClick(v);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
|
||||
if (animationView instanceof FingerprintFindSensorAnimation) {
|
||||
mAnimation = (FingerprintFindSensorAnimation) animationView;
|
||||
@@ -127,6 +176,8 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
protected int getContentView() {
|
||||
if (mCanAssumeUdfps) {
|
||||
return R.layout.udfps_enroll_find_sensor_layout;
|
||||
} else if (mCanAssumeSidefps) {
|
||||
return R.layout.sfps_enroll_find_sensor_layout;
|
||||
}
|
||||
return R.layout.fingerprint_enroll_find_sensor;
|
||||
}
|
||||
@@ -202,6 +253,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
stopListenOrientationEvent();
|
||||
super.onDestroy();
|
||||
if (mAnimation != null) {
|
||||
mAnimation.stopAnimation();
|
||||
@@ -279,4 +331,37 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.FINGERPRINT_FIND_SENSOR;
|
||||
}
|
||||
|
||||
private void listenOrientationEvent() {
|
||||
if (!mCanAssumeSidefps) {
|
||||
// Do nothing if the device doesn't support SideFPS.
|
||||
return;
|
||||
}
|
||||
mOrientationEventListener = new OrientationEventListener(this) {
|
||||
@Override
|
||||
public void onOrientationChanged(int orientation) {
|
||||
final int currentRotation = getDisplay().getRotation();
|
||||
if ((mPreviousRotation == Surface.ROTATION_90
|
||||
&& currentRotation == Surface.ROTATION_270) || (
|
||||
mPreviousRotation == Surface.ROTATION_270
|
||||
&& currentRotation == Surface.ROTATION_90)) {
|
||||
mPreviousRotation = currentRotation;
|
||||
recreate();
|
||||
}
|
||||
}
|
||||
};
|
||||
mOrientationEventListener.enable();
|
||||
mPreviousRotation = getDisplay().getRotation();
|
||||
}
|
||||
|
||||
private void stopListenOrientationEvent() {
|
||||
if (!mCanAssumeSidefps) {
|
||||
// Do nothing if the device doesn't support SideFPS.
|
||||
return;
|
||||
}
|
||||
if (mOrientationEventListener != null) {
|
||||
mOrientationEventListener.disable();
|
||||
}
|
||||
mOrientationEventListener = null;
|
||||
}
|
||||
}
|
||||
|
@@ -44,6 +44,7 @@ import com.android.settingslib.HelpUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
import com.google.android.setupdesign.span.LinkSpan;
|
||||
|
||||
import java.util.List;
|
||||
@@ -203,6 +204,7 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
@Override
|
||||
protected int checkMaxEnrolled() {
|
||||
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
if (mFingerprintManager != null) {
|
||||
final List<FingerprintSensorPropertiesInternal> props =
|
||||
mFingerprintManager.getSensorPropertiesInternal();
|
||||
@@ -210,13 +212,22 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
final int max = props.get(0).maxEnrollmentsPerUser;
|
||||
final int numEnrolledFingerprints =
|
||||
mFingerprintManager.getEnrolledFingerprints(mUserId).size();
|
||||
if (numEnrolledFingerprints >= max) {
|
||||
final int maxFingerprintsEnrollableIfSUW = getApplicationContext().getResources()
|
||||
.getInteger(R.integer.suw_max_fingerprints_enrollable);
|
||||
if (isSetupWizard) {
|
||||
if (numEnrolledFingerprints >= maxFingerprintsEnrollableIfSUW) {
|
||||
return R.string.fingerprint_intro_error_max;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (numEnrolledFingerprints >= max) {
|
||||
return R.string.fingerprint_intro_error_max;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return R.string.fingerprint_intro_error_unknown;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -31,12 +31,18 @@ import com.android.settings.biometrics.BiometricErrorDialog;
|
||||
*/
|
||||
public class FingerprintErrorDialog extends BiometricErrorDialog {
|
||||
public static void showErrorDialog(BiometricEnrollBase host, int errMsgId) {
|
||||
if (host.isFinishing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final FragmentManager fragmentManager = host.getSupportFragmentManager();
|
||||
if (fragmentManager.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CharSequence errMsg = host.getText(getErrorMessage(errMsgId));
|
||||
final FingerprintErrorDialog dialog = newInstance(errMsg, errMsgId);
|
||||
final FragmentManager fragmentManager = host.getSupportFragmentManager();
|
||||
if (!fragmentManager.isDestroyed()) {
|
||||
dialog.show(fragmentManager, FingerprintErrorDialog.class.getName());
|
||||
}
|
||||
dialog.show(fragmentManager, FingerprintErrorDialog.class.getName());
|
||||
}
|
||||
|
||||
private static int getErrorMessage(int errMsgId) {
|
||||
|
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.bluetooth;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
|
||||
/**
|
||||
* Controller that shows received files
|
||||
*/
|
||||
public class BluetoothFilesPreferenceController extends BasePreferenceController
|
||||
implements PreferenceControllerMixin {
|
||||
private static final String TAG = "BluetoothFilesPrefCtrl";
|
||||
|
||||
public static final String KEY_RECEIVED_FILES = "bt_received_files";
|
||||
|
||||
/* Private intent to show the list of received files */
|
||||
@VisibleForTesting
|
||||
static final String ACTION_OPEN_FILES = "com.android.bluetooth.action.TransferHistory";
|
||||
@VisibleForTesting
|
||||
static final String EXTRA_SHOW_ALL_FILES = "android.btopp.intent.extra.SHOW_ALL";
|
||||
@VisibleForTesting
|
||||
static final String EXTRA_DIRECTION = "direction";
|
||||
|
||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
|
||||
public BluetoothFilesPreferenceController(Context context) {
|
||||
super(context, KEY_RECEIVED_FILES);
|
||||
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
|
||||
? AVAILABLE
|
||||
: UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY_RECEIVED_FILES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (KEY_RECEIVED_FILES.equals(preference.getKey())) {
|
||||
mMetricsFeatureProvider.action(mContext,
|
||||
SettingsEnums.ACTION_BLUETOOTH_FILES);
|
||||
Intent intent = new Intent(ACTION_OPEN_FILES);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent.putExtra(EXTRA_DIRECTION, 1 /* DIRECTION_INBOUND */);
|
||||
intent.putExtra(EXTRA_SHOW_ALL_FILES, true);
|
||||
mContext.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -188,7 +188,8 @@ public final class BluetoothPairingService extends Service {
|
||||
}
|
||||
|
||||
PendingIntent pairIntent = PendingIntent.getService(this, 0, pairingDialogIntent,
|
||||
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
|
||||
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT
|
||||
| PendingIntent.FLAG_IMMUTABLE);
|
||||
|
||||
Intent serviceIntent = new Intent(ACTION_DISMISS_PAIRING);
|
||||
serviceIntent.setClass(this, BluetoothPairingService.class);
|
||||
|
@@ -98,7 +98,8 @@ public class BluetoothSliceBuilder {
|
||||
SettingsSlicesContract.KEY_BLUETOOTH).build();
|
||||
return SliceBuilderUtils.buildSearchResultPageIntent(context,
|
||||
BluetoothDashboardFragment.class.getName(), null /* key */, screenTitle,
|
||||
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY)
|
||||
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY,
|
||||
R.string.menu_key_connected_devices)
|
||||
.setClassName(context.getPackageName(), SubSettings.class.getName())
|
||||
.setData(contentUri);
|
||||
}
|
||||
|
@@ -29,7 +29,6 @@ import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
@@ -73,8 +72,6 @@ public class ForgetDeviceDialogFragment extends InstrumentedDialogFragment {
|
||||
};
|
||||
Context context = getContext();
|
||||
mDevice = getDevice(context);
|
||||
final boolean untetheredHeadset = BluetoothUtils.getBooleanMetaData(
|
||||
mDevice.getDevice(), BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
.setPositiveButton(R.string.bluetooth_unpair_dialog_forget_confirm_button,
|
||||
@@ -82,9 +79,7 @@ public class ForgetDeviceDialogFragment extends InstrumentedDialogFragment {
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
dialog.setTitle(R.string.bluetooth_unpair_dialog_title);
|
||||
dialog.setMessage(context.getString(untetheredHeadset
|
||||
? R.string.bluetooth_untethered_unpair_dialog_body
|
||||
: R.string.bluetooth_unpair_dialog_body,
|
||||
dialog.setMessage(context.getString(R.string.bluetooth_unpair_dialog_body,
|
||||
mDevice.getName()));
|
||||
return dialog;
|
||||
}
|
||||
|
@@ -21,11 +21,11 @@ import android.content.pm.PackageManager;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.BluetoothFilesPreferenceController;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.nfc.AndroidBeamPreferenceController;
|
||||
import com.android.settings.print.PrintSettingPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.uwb.UwbPreferenceController;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
@@ -43,6 +43,7 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
|
||||
private static final String TAG = "AdvancedConnectedDeviceFrag";
|
||||
|
||||
static final String KEY_BLUETOOTH = "bluetooth_settings";
|
||||
static final String KEY_UWB = "uwb_settings";
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -64,6 +65,15 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
|
||||
return R.xml.connected_devices_advanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
UwbPreferenceController uwbPreferenceController = use(UwbPreferenceController.class);
|
||||
if (uwbPreferenceController != null && getSettingsLifecycle() != null) {
|
||||
getSettingsLifecycle().addObserver(uwbPreferenceController);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
return buildControllers(context, getSettingsLifecycle());
|
||||
@@ -73,8 +83,6 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
|
||||
Lifecycle lifecycle) {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
|
||||
controllers.add(new BluetoothFilesPreferenceController(context));
|
||||
|
||||
final PrintSettingPreferenceController printerController =
|
||||
new PrintSettingPreferenceController(context);
|
||||
|
||||
|
@@ -158,8 +158,7 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc
|
||||
switch (newState) {
|
||||
case RecyclerView.SCROLL_STATE_DRAGGING:
|
||||
final Configuration.Builder builder =
|
||||
new Configuration.Builder(CUJ_SETTINGS_PAGE_SCROLL)
|
||||
.setView(recyclerView)
|
||||
Configuration.Builder.withView(CUJ_SETTINGS_PAGE_SCROLL, recyclerView)
|
||||
.setTag(mClassName);
|
||||
mMonitor.begin(builder);
|
||||
break;
|
||||
|
@@ -73,7 +73,8 @@ public class PreferenceXmlParserUtils {
|
||||
MetadataFlag.FLAG_NEED_PREF_ICON,
|
||||
MetadataFlag.FLAG_NEED_SEARCHABLE,
|
||||
MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE,
|
||||
MetadataFlag.FLAG_FOR_WORK})
|
||||
MetadataFlag.FLAG_FOR_WORK,
|
||||
MetadataFlag.FLAG_NEED_HIGHLIGHTABLE_MENU_KEY})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface MetadataFlag {
|
||||
|
||||
@@ -89,6 +90,7 @@ public class PreferenceXmlParserUtils {
|
||||
int FLAG_NEED_PREF_APPEND = 1 << 10;
|
||||
int FLAG_UNAVAILABLE_SLICE_SUBTITLE = 1 << 11;
|
||||
int FLAG_FOR_WORK = 1 << 12;
|
||||
int FLAG_NEED_HIGHLIGHTABLE_MENU_KEY = 1 << 13;
|
||||
}
|
||||
|
||||
public static final String METADATA_PREF_TYPE = "type";
|
||||
@@ -102,6 +104,7 @@ public class PreferenceXmlParserUtils {
|
||||
public static final String METADATA_APPEND = "staticPreferenceLocation";
|
||||
public static final String METADATA_UNAVAILABLE_SLICE_SUBTITLE = "unavailable_slice_subtitle";
|
||||
public static final String METADATA_FOR_WORK = "for_work";
|
||||
public static final String METADATA_HIGHLIGHTABLE_MENU_KEY = "highlightable_menu_key";
|
||||
|
||||
private static final String ENTRIES_SEPARATOR = "|";
|
||||
|
||||
@@ -250,6 +253,10 @@ public class PreferenceXmlParserUtils {
|
||||
preferenceMetadata.putBoolean(METADATA_FOR_WORK,
|
||||
isForWork(preferenceAttributes));
|
||||
}
|
||||
if (hasFlag(flags, MetadataFlag.FLAG_NEED_HIGHLIGHTABLE_MENU_KEY)) {
|
||||
preferenceMetadata.putString(METADATA_HIGHLIGHTABLE_MENU_KEY,
|
||||
getHighlightableMenuKey(preferenceAttributes));
|
||||
}
|
||||
metadata.add(preferenceMetadata);
|
||||
|
||||
preferenceAttributes.recycle();
|
||||
@@ -314,6 +321,10 @@ public class PreferenceXmlParserUtils {
|
||||
return styledAttributes.getString(R.styleable.Preference_controller);
|
||||
}
|
||||
|
||||
private static String getHighlightableMenuKey(TypedArray styledAttributes) {
|
||||
return styledAttributes.getString(R.styleable.Preference_highlightableMenuKey);
|
||||
}
|
||||
|
||||
private static int getIcon(TypedArray styledAttributes) {
|
||||
return styledAttributes.getResourceId(com.android.internal.R.styleable.Icon_icon, 0);
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.core.CategoryMixin.CategoryHandler;
|
||||
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
|
||||
@@ -73,6 +74,9 @@ public class SettingsBaseActivity extends FragmentActivity implements CategoryHa
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (isFinishing()) {
|
||||
return;
|
||||
}
|
||||
if (isLockTaskModePinned() && !isSettingsRunOnTop()) {
|
||||
Log.w(TAG, "Devices lock task mode pinned.");
|
||||
finish();
|
||||
@@ -91,17 +95,14 @@ public class SettingsBaseActivity extends FragmentActivity implements CategoryHa
|
||||
// Apply SetupWizard light theme during setup flow. This is for SubSettings pages.
|
||||
final boolean isAnySetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
if (isAnySetupWizard && this instanceof SubSettings) {
|
||||
int appliedTheme;
|
||||
if (ThemeHelper.trySetDynamicColor(this)) {
|
||||
appliedTheme = ThemeHelper.isSetupWizardDayNightEnabled(this)
|
||||
final int appliedTheme = ThemeHelper.isSetupWizardDayNightEnabled(this)
|
||||
? R.style.SudDynamicColorThemeSettings_SetupWizard_DayNight
|
||||
: R.style.SudDynamicColorThemeSettings_SetupWizard;
|
||||
setTheme(appliedTheme);
|
||||
} else {
|
||||
appliedTheme = ThemeHelper.isSetupWizardDayNightEnabled(this)
|
||||
? R.style.SubSettings_SetupWizard
|
||||
: R.style.SudThemeGlifV3_Light;
|
||||
setTheme(SetupWizardUtils.getTheme(this, getIntent()));
|
||||
}
|
||||
setTheme(appliedTheme);
|
||||
}
|
||||
|
||||
if (isToolbarEnabled() && !isAnySetupWizard) {
|
||||
@@ -186,19 +187,17 @@ public class SettingsBaseActivity extends FragmentActivity implements CategoryHa
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
super.setTitle(title);
|
||||
if (mCollapsingToolbarLayout != null) {
|
||||
mCollapsingToolbarLayout.setTitle(title);
|
||||
} else {
|
||||
super.setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int titleId) {
|
||||
super.setTitle(getText(titleId));
|
||||
if (mCollapsingToolbarLayout != null) {
|
||||
mCollapsingToolbarLayout.setTitle(getText(titleId));
|
||||
} else {
|
||||
super.setTitle(titleId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -89,4 +89,7 @@ public abstract class TogglePreferenceController extends BasePreferenceControlle
|
||||
public boolean isPublicSlice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract int getSliceHighlightMenuRes();
|
||||
}
|
@@ -29,6 +29,7 @@ import com.android.settings.accessibility.AccessibilityDetailsSettingsFragment;
|
||||
import com.android.settings.accessibility.AccessibilitySettings;
|
||||
import com.android.settings.accessibility.AccessibilitySettingsForSetupWizard;
|
||||
import com.android.settings.accessibility.CaptionPropertiesFragment;
|
||||
import com.android.settings.accessibility.ToggleColorInversionPreferenceFragment;
|
||||
import com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment;
|
||||
import com.android.settings.accessibility.ToggleReduceBrightColorsPreferenceFragment;
|
||||
import com.android.settings.accounts.AccountDashboardFragment;
|
||||
@@ -67,6 +68,7 @@ import com.android.settings.biometrics.combination.CombinedBiometricSettings;
|
||||
import com.android.settings.biometrics.face.FaceSettings;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintSettings;
|
||||
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
|
||||
import com.android.settings.bluetooth.BluetoothPairingDetail;
|
||||
import com.android.settings.bugreporthandler.BugReportHandlerPicker;
|
||||
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
|
||||
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
|
||||
@@ -119,6 +121,7 @@ import com.android.settings.network.NetworkDashboardFragment;
|
||||
import com.android.settings.network.NetworkProviderSettings;
|
||||
import com.android.settings.network.apn.ApnEditor;
|
||||
import com.android.settings.network.apn.ApnSettings;
|
||||
import com.android.settings.network.telephony.NetworkSelectSettings;
|
||||
import com.android.settings.nfc.AndroidBeam;
|
||||
import com.android.settings.nfc.PaymentSettings;
|
||||
import com.android.settings.notification.ConfigureNotificationSettings;
|
||||
@@ -175,6 +178,7 @@ public class SettingsGateway {
|
||||
public static final String[] ENTRY_FRAGMENTS = {
|
||||
AdvancedConnectedDeviceDashboardFragment.class.getName(),
|
||||
CreateShortcut.class.getName(),
|
||||
BluetoothPairingDetail.class.getName(),
|
||||
WifiSettings.class.getName(),
|
||||
WifiNetworkDetailsFragment.class.getName(),
|
||||
ConfigureWifiSettings.class.getName(),
|
||||
@@ -215,6 +219,7 @@ public class SettingsGateway {
|
||||
AccessibilitySettingsForSetupWizard.class.getName(),
|
||||
CaptionPropertiesFragment.class.getName(),
|
||||
ToggleDaltonizerPreferenceFragment.class.getName(),
|
||||
ToggleColorInversionPreferenceFragment.class.getName(),
|
||||
ToggleReduceBrightColorsPreferenceFragment.class.getName(),
|
||||
TextToSpeechSettings.class.getName(),
|
||||
PrivateVolumeForget.class.getName(),
|
||||
@@ -317,6 +322,7 @@ public class SettingsGateway {
|
||||
InteractAcrossProfilesDetails.class.getName(),
|
||||
MediaControlsSettings.class.getName(),
|
||||
NetworkProviderSettings.class.getName(),
|
||||
NetworkSelectSettings.class.getName(),
|
||||
AlarmsAndRemindersDetails.class.getName(),
|
||||
MediaManagementAppsDetails.class.getName(),
|
||||
AutoBrightnessSettings.class.getName()
|
||||
@@ -341,6 +347,7 @@ public class SettingsGateway {
|
||||
Settings.WifiSettingsActivity.class.getName(),
|
||||
Settings.DataUsageSummaryActivity.class.getName(),
|
||||
Settings.NetworkProviderSettingsActivity.class.getName(),
|
||||
Settings.NetworkSelectActivity.class.getName(),
|
||||
// Home page > Connected devices
|
||||
Settings.BluetoothSettingsActivity.class.getName(),
|
||||
Settings.WifiDisplaySettingsActivity.class.getName(),
|
||||
|
@@ -17,6 +17,7 @@ package com.android.settings.dashboard;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
@@ -24,6 +25,7 @@ import android.util.Pair;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.homepage.HighlightableMenu;
|
||||
import com.android.settingslib.applications.InterestingConfigChanges;
|
||||
import com.android.settingslib.drawer.CategoryKey;
|
||||
import com.android.settingslib.drawer.DashboardCategory;
|
||||
@@ -153,6 +155,20 @@ public class CategoryManager {
|
||||
filterDuplicateTiles(mCategoryByKeyMap);
|
||||
if (firstLoading) {
|
||||
logTiles(context);
|
||||
|
||||
final DashboardCategory homepageCategory = mCategoryByKeyMap.get(
|
||||
CategoryKey.CATEGORY_HOMEPAGE);
|
||||
if (homepageCategory == null) {
|
||||
return;
|
||||
}
|
||||
for (Tile tile : homepageCategory.getTiles()) {
|
||||
final String key = tile.getKey(context);
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
Log.w(TAG, "Key hint missing for homepage tile: " + tile.getTitle(context));
|
||||
continue;
|
||||
}
|
||||
HighlightableMenu.addMenuKey(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -47,9 +47,9 @@ public interface DashboardFeatureProvider {
|
||||
* Binds preference to data provided by tile and gets dynamic data observers.
|
||||
*
|
||||
* @param activity If tile contains intent to launch, it will be launched from this activity
|
||||
* @param fragment The fragment that the preference will be bound to
|
||||
* @param forceRoundedIcon Whether or not injected tiles from other packages should be forced to
|
||||
* rounded icon.
|
||||
* @param sourceMetricsCategory The context (source) from which an action is performed
|
||||
* @param pref The preference to bind data
|
||||
* @param tile The binding data
|
||||
* @param key They key for preference. If null, we will generate one from tile data
|
||||
@@ -58,7 +58,7 @@ public interface DashboardFeatureProvider {
|
||||
* @return The list of dynamic data observers
|
||||
*/
|
||||
List<DynamicDataObserver> bindPreferenceToTileAndGetObservers(FragmentActivity activity,
|
||||
boolean forceRoundedIcon, int sourceMetricsCategory, Preference pref, Tile tile,
|
||||
DashboardFragment fragment, boolean forceRoundedIcon, Preference pref, Tile tile,
|
||||
String key, int baseOrder);
|
||||
|
||||
/**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user