Merge 25Q1 (ab/12770256) to aosp-main-future
Bug: 385190204 Merged-In: Iaee6792d1a27be8fa4b443f783a47a3715b6d3a1 Change-Id: I0ac29cecfec526a38cf4a120b8ef704ee7bc01b3
This commit is contained in:
@@ -147,9 +147,24 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener {
|
||||
* @return any subscription within device is under ECM mode
|
||||
*/
|
||||
public boolean isInEcmMode() {
|
||||
return isInEcmMode(mContext, mTelephonyManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the status of ECM mode
|
||||
*
|
||||
* @param context Caller's {@link Context}
|
||||
* @param telephonyManager The default {@link TelephonyManager}
|
||||
*
|
||||
* @return any subscription within device is under ECM mode
|
||||
*/
|
||||
public static boolean isInEcmMode(Context context, TelephonyManager telephonyManager) {
|
||||
if (context == null || telephonyManager == null) {
|
||||
return false;
|
||||
}
|
||||
if (Flags.enforceTelephonyFeatureMappingForPublicApis()) {
|
||||
try {
|
||||
if (mTelephonyManager.getEmergencyCallbackMode()) {
|
||||
if (telephonyManager.getEmergencyCallbackMode()) {
|
||||
return true;
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
@@ -157,26 +172,26 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener {
|
||||
// Ignore exception, device is not in ECM mode.
|
||||
}
|
||||
} else {
|
||||
if (mTelephonyManager.getEmergencyCallbackMode()) {
|
||||
if (telephonyManager.getEmergencyCallbackMode()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final List<SubscriptionInfo> subInfoList =
|
||||
ProxySubscriptionManager.getInstance(mContext).getActiveSubscriptionsInfo();
|
||||
ProxySubscriptionManager.getInstance(context).getActiveSubscriptionsInfo();
|
||||
if (subInfoList == null) {
|
||||
return false;
|
||||
}
|
||||
for (SubscriptionInfo subInfo : subInfoList) {
|
||||
final TelephonyManager telephonyManager =
|
||||
mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId());
|
||||
if (telephonyManager != null) {
|
||||
final TelephonyManager telephonyManagerForSubId =
|
||||
telephonyManager.createForSubscriptionId(subInfo.getSubscriptionId());
|
||||
if (telephonyManagerForSubId != null) {
|
||||
if (!Flags.enforceTelephonyFeatureMappingForPublicApis()) {
|
||||
if (telephonyManager.getEmergencyCallbackMode()) {
|
||||
if (telephonyManagerForSubId.getEmergencyCallbackMode()) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (telephonyManager.getEmergencyCallbackMode()) {
|
||||
if (telephonyManagerForSubId.getEmergencyCallbackMode()) {
|
||||
return true;
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
|
||||
@@ -20,9 +20,13 @@ import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.display.BrightnessLevelPreferenceController;
|
||||
import com.android.settings.display.CameraGesturePreferenceController;
|
||||
import com.android.settings.display.DisplayScreen;
|
||||
import com.android.settings.display.LiftToWakePreferenceController;
|
||||
import com.android.settings.display.ShowOperatorNamePreferenceController;
|
||||
import com.android.settings.display.TapToWakePreferenceController;
|
||||
@@ -92,4 +96,9 @@ public class DisplaySettings extends DashboardFragment {
|
||||
return buildPreferenceControllers(context, null);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
|
||||
return DisplayScreen.KEY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,13 @@
|
||||
package com.android.settings;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.deviceinfo.legal.LegalSettingsScreen;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
@@ -44,4 +49,9 @@ public class LegalSettings extends DashboardFragment {
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.about_legal);
|
||||
|
||||
@Override
|
||||
public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
|
||||
return LegalSettingsScreen.KEY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.settings;
|
||||
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
@@ -25,6 +27,7 @@ import android.app.admin.FactoryResetProtectionPolicy;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
@@ -33,6 +36,7 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.oemlock.OemLockManager;
|
||||
import android.service.persistentdata.PersistentDataBlockManager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -42,6 +46,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.core.InstrumentedFragment;
|
||||
import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
|
||||
import com.android.settings.network.telephony.SubscriptionActionDialogActivity;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
@@ -90,7 +95,7 @@ public class MainClearConfirm extends InstrumentedFragment {
|
||||
} else {
|
||||
pdbManager = null;
|
||||
}
|
||||
|
||||
setSimDialogProgressState();
|
||||
if (shouldWipePersistentDataBlock(pdbManager)) {
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@@ -128,6 +133,17 @@ public class MainClearConfirm extends InstrumentedFragment {
|
||||
} else {
|
||||
doMainClear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setSimDialogProgressState() {
|
||||
if (getActivity() != null) {
|
||||
final SharedPreferences prefs = getActivity().getSharedPreferences(
|
||||
SubscriptionActionDialogActivity.SIM_ACTION_DIALOG_PREFS, MODE_PRIVATE);
|
||||
prefs.edit().putInt(SubscriptionActionDialogActivity.KEY_PROGRESS_STATE,
|
||||
SubscriptionActionDialogActivity.PROGRESS_IS_SHOWING).apply();
|
||||
Log.d(TAG, "SIM dialog setProgressState: 1");
|
||||
}
|
||||
}
|
||||
|
||||
private ProgressDialog getProgressDialog() {
|
||||
|
||||
59
src/com/android/settings/PreferenceRestrictionMixin.kt
Normal file
59
src/com/android/settings/PreferenceRestrictionMixin.kt
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.content.Context
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import androidx.annotation.CallSuper
|
||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal
|
||||
import com.android.settingslib.metadata.PreferenceRestrictionProvider
|
||||
|
||||
/** Mixin to support restriction. */
|
||||
interface PreferenceRestrictionMixin : PreferenceRestrictionProvider {
|
||||
|
||||
/**
|
||||
* Keys for restriction.
|
||||
*
|
||||
* Preference is restricted when **ANY** key in the list is restricted.
|
||||
*/
|
||||
val restrictionKeys: Array<String>
|
||||
|
||||
val useAdminDisabledSummary: Boolean
|
||||
get() = false
|
||||
|
||||
@CallSuper fun isEnabled(context: Context) = !context.hasBaseUserRestriction(restrictionKeys)
|
||||
|
||||
override fun isRestricted(context: Context) =
|
||||
context.getRestrictionEnforcedAdmin(restrictionKeys) != null
|
||||
}
|
||||
|
||||
/** Returns the admin that has enforced restriction on given keys. */
|
||||
fun Context.getRestrictionEnforcedAdmin(restrictionKeys: Array<String>): EnforcedAdmin? {
|
||||
val userId = UserHandle.myUserId()
|
||||
return restrictionKeys.firstNotNullOfOrNull {
|
||||
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(this, it, userId)
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns if there is **any** base user restriction on given keys. */
|
||||
fun Context.hasBaseUserRestriction(restrictionKeys: Array<String>): Boolean {
|
||||
val userManager = getSystemService(UserManager::class.java) ?: return false
|
||||
val userHandle = UserHandle.of(UserHandle.myUserId())
|
||||
return restrictionKeys.any { userManager.hasBaseUserRestriction(it, userHandle) }
|
||||
}
|
||||
@@ -69,6 +69,6 @@ class RegulatoryInfoDisplayActivity : Activity() {
|
||||
private fun getRegulatoryText(): CharSequence? {
|
||||
val regulatoryInfoText = resources.getText(R.string.regulatory_info_text)
|
||||
if (regulatoryInfoText.isNotBlank()) return regulatoryInfoText
|
||||
return featureFactory.hardwareInfoFeatureProvider?.countryIfOriginLabel
|
||||
return featureFactory.hardwareInfoFeatureProvider?.countryOfOriginLabel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.telephony.flags.Flags;
|
||||
import com.android.settings.core.InstrumentedFragment;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.network.ResetNetworkRestrictionViewBuilder;
|
||||
@@ -142,13 +141,10 @@ public class ResetNetwork extends InstrumentedFragment {
|
||||
Context context = getContext();
|
||||
boolean resetSims = false;
|
||||
|
||||
// TODO(b/317276437) Simplify the logic once flag is released
|
||||
int resetOptions = ResetNetworkRequest.RESET_CONNECTIVITY_MANAGER
|
||||
| ResetNetworkRequest.RESET_VPN_MANAGER;
|
||||
if (Flags.resetMobileNetworkSettings()) {
|
||||
resetOptions |= ResetNetworkRequest.RESET_IMS_STACK;
|
||||
resetOptions |= ResetNetworkRequest.RESET_PHONE_PROCESS;
|
||||
}
|
||||
| ResetNetworkRequest.RESET_VPN_MANAGER
|
||||
| ResetNetworkRequest.RESET_IMS_STACK
|
||||
| ResetNetworkRequest.RESET_PHONE_PROCESS;
|
||||
ResetNetworkRequest request = new ResetNetworkRequest(resetOptions);
|
||||
if (mSubscriptions != null && mSubscriptions.size() > 0) {
|
||||
int selectedIndex = mSubscriptionSpinner.getSelectedItemPosition();
|
||||
@@ -156,9 +152,7 @@ public class ResetNetwork extends InstrumentedFragment {
|
||||
int subId = subscription.getSubscriptionId();
|
||||
request.setResetTelephonyAndNetworkPolicyManager(subId)
|
||||
.setResetApn(subId);
|
||||
if (Flags.resetMobileNetworkSettings()) {
|
||||
request.setResetImsSubId(subId);
|
||||
}
|
||||
request.setResetImsSubId(subId);
|
||||
}
|
||||
if (mEsimContainer.getVisibility() == View.VISIBLE && mEsimCheckbox.isChecked()) {
|
||||
resetSims = true;
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.widget.CheckedTextView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AlertDialog.Builder;
|
||||
import androidx.preference.ListPreferenceDialogFragmentCompat;
|
||||
@@ -40,11 +41,14 @@ import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedPreferenceHelper;
|
||||
import com.android.settingslib.RestrictedPreferenceHelperProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RestrictedListPreference extends CustomListPreference {
|
||||
public class RestrictedListPreference extends CustomListPreference implements
|
||||
RestrictedPreferenceHelperProvider {
|
||||
|
||||
private final RestrictedPreferenceHelper mHelper;
|
||||
private final List<RestrictedItem> mRestrictedItems = new ArrayList<>();
|
||||
private boolean mRequiresActiveUnlockedProfile = false;
|
||||
@@ -61,6 +65,11 @@ public class RestrictedListPreference extends CustomListPreference {
|
||||
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
|
||||
return mHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
|
||||
@@ -92,13 +92,17 @@ public class Settings extends SettingsActivity {
|
||||
public static class AvailableVirtualKeyboardActivity extends SettingsActivity { /* empty */ }
|
||||
public static class KeyboardLayoutPickerActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PhysicalKeyboardActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PhysicalKeyboardLayoutPickerActivity extends SettingsActivity {
|
||||
/* empty */
|
||||
}
|
||||
public static class InputMethodAndSubtypeEnablerActivity extends SettingsActivity { /* empty */ }
|
||||
public static class SpellCheckersSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class LocalePickerActivity extends SettingsActivity { /* empty */ }
|
||||
public static class LanguageAndInputSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class LanguageSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity for the regional preferences settings. */
|
||||
public static class RegionalPreferencesActivity extends SettingsActivity { /* empty */ }
|
||||
public static class TemperatureUnitSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class FirstDayOfWeekSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class KeyboardSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity for the navigation mode settings. */
|
||||
public static class NavigationModeSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
@@ -112,6 +116,7 @@ public class Settings extends SettingsActivity {
|
||||
public static class ModuleLicensesActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AppStorageSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ManageAssistActivity extends SettingsActivity { /* empty */ }
|
||||
public static class HighPowerApplicationsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class BackgroundCheckSummaryActivity extends SettingsActivity { /* empty */ }
|
||||
@@ -485,6 +490,7 @@ public class Settings extends SettingsActivity {
|
||||
public static class NetworkDashboardActivity extends SettingsActivity {}
|
||||
public static class ConnectedDeviceDashboardActivity extends SettingsActivity {}
|
||||
public static class PowerUsageSummaryActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PowerUsageAdvancedActivity extends SettingsActivity { /* empty */ }
|
||||
public static class StorageDashboardActivity extends SettingsActivity {}
|
||||
public static class AccountDashboardActivity extends SettingsActivity {}
|
||||
public static class SystemDashboardActivity extends SettingsActivity {}
|
||||
@@ -515,4 +521,5 @@ public class Settings extends SettingsActivity {
|
||||
|
||||
public static class HearingDevicesActivity extends SettingsActivity { /* empty */ }
|
||||
public static class HearingDevicesPairingActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ContactsStorageSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ import com.android.settings.widget.SettingsMainSwitchBar;
|
||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||
import com.android.settingslib.core.instrumentation.SharedPreferencesLogger;
|
||||
import com.android.settingslib.drawer.DashboardCategory;
|
||||
import com.android.settingslib.widget.SettingsThemeHelper;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
@@ -169,6 +170,9 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
|
||||
private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
|
||||
|
||||
private static final int EXPRESSIVE_BACK_ICON =
|
||||
com.android.settingslib.collapsingtoolbar.R.drawable.settingslib_expressive_icon_back;
|
||||
|
||||
private String mFragmentClass;
|
||||
private String mHighlightMenuKey;
|
||||
|
||||
@@ -301,10 +305,17 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
// If this is in setup flow, don't apply theme. Because light theme needs to be applied
|
||||
// in SettingsBaseActivity#onCreate().
|
||||
if (isSubSettings(intent) && !WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
setTheme(R.style.Theme_SubSettings);
|
||||
int themeId = SettingsThemeHelper.isExpressiveTheme(this)
|
||||
? R.style.Theme_SubSettings_Expressive : R.style.Theme_SubSettings;
|
||||
setTheme(themeId);
|
||||
}
|
||||
|
||||
setContentView(R.layout.settings_main_prefs);
|
||||
mMainSwitch = findViewById(R.id.switch_bar);
|
||||
if (mMainSwitch != null) {
|
||||
mMainSwitch.setMetricsCategory(lookupMetricsCategory());
|
||||
mMainSwitch.setTranslationZ(findViewById(R.id.main_content).getTranslationZ() + 1);
|
||||
}
|
||||
|
||||
getSupportFragmentManager().addOnBackStackChangedListener(this);
|
||||
|
||||
@@ -324,12 +335,6 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
launchSettingFragment(initialFragmentName, intent);
|
||||
}
|
||||
|
||||
mMainSwitch = findViewById(R.id.switch_bar);
|
||||
if (mMainSwitch != null) {
|
||||
mMainSwitch.setMetricsCategory(lookupMetricsCategory());
|
||||
mMainSwitch.setTranslationZ(findViewById(R.id.main_content).getTranslationZ() + 1);
|
||||
}
|
||||
|
||||
// see if we should show Back/Next buttons
|
||||
if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
|
||||
|
||||
@@ -388,6 +393,9 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(isActionBarButtonEnabled);
|
||||
actionBar.setHomeButtonEnabled(isActionBarButtonEnabled);
|
||||
if (SettingsThemeHelper.isExpressiveTheme(this)) {
|
||||
actionBar.setHomeAsUpIndicator(EXPRESSIVE_BACK_ICON);
|
||||
}
|
||||
actionBar.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -45,6 +46,7 @@ import com.android.settingslib.datastore.BackupRestoreStorageManager;
|
||||
import com.android.settingslib.metadata.PreferenceScreenMetadata;
|
||||
import com.android.settingslib.metadata.PreferenceScreenRegistry;
|
||||
import com.android.settingslib.metadata.ProvidePreferenceScreenOptions;
|
||||
import com.android.settingslib.preference.PreferenceBindingFactory;
|
||||
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
@@ -58,8 +60,9 @@ import java.util.List;
|
||||
)
|
||||
public class SettingsApplication extends Application {
|
||||
|
||||
private static final String TAG = "SettingsApplication";
|
||||
private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null);
|
||||
@Nullable private BiometricsEnvironment mBiometricsEnvironment;
|
||||
@Nullable volatile private BiometricsEnvironment mBiometricsEnvironment;
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
@@ -74,6 +77,7 @@ public class SettingsApplication extends Application {
|
||||
if (Flags.catalyst()) {
|
||||
PreferenceScreenRegistry.INSTANCE.setPreferenceScreensSupplier(
|
||||
this::getPreferenceScreens);
|
||||
PreferenceBindingFactory.setDefaultFactory(new SettingsPreferenceBindingFactory());
|
||||
}
|
||||
|
||||
BackupRestoreStorageManager.getInstance(this)
|
||||
@@ -138,20 +142,23 @@ public class SettingsApplication extends Application {
|
||||
|
||||
@Nullable
|
||||
public BiometricsEnvironment getBiometricEnvironment() {
|
||||
if (Flags.fingerprintV2Enrollment()) {
|
||||
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
||||
final FingerprintManager fpm = getSystemService(FingerprintManager.class);
|
||||
if (mBiometricsEnvironment == null) {
|
||||
mBiometricsEnvironment = new BiometricsEnvironment(this, fpm);
|
||||
BiometricsEnvironment localEnvironment = mBiometricsEnvironment;
|
||||
if (localEnvironment == null) {
|
||||
synchronized (this) {
|
||||
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
|
||||
return null;
|
||||
}
|
||||
final FingerprintManager fpm = getSystemService(FingerprintManager.class);
|
||||
localEnvironment = mBiometricsEnvironment;
|
||||
if (fpm != null && localEnvironment == null) {
|
||||
mBiometricsEnvironment = localEnvironment = new BiometricsEnvironment(this,
|
||||
fpm);
|
||||
} else {
|
||||
Log.e(TAG, "Error when creating environment, fingerprint manager was null");
|
||||
}
|
||||
return mBiometricsEnvironment;
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
return localEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,6 +39,7 @@ import android.util.Log;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
|
||||
import com.android.settings.core.instrumentation.ElapsedTimeUtils;
|
||||
import com.android.settings.homepage.DeepLinkHomepageActivity;
|
||||
import com.android.settings.search.SearchStateReceiver;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
@@ -69,6 +70,7 @@ public class SettingsInitialize extends BroadcastReceiver {
|
||||
webviewSettingSetup(context, pm, userInfo);
|
||||
ThreadUtils.postOnBackgroundThread(() -> refreshExistingShortcuts(context));
|
||||
enableTwoPaneDeepLinkActivityIfNecessary(pm, context);
|
||||
storeSuwCompleteTimestamp(context, broadcast);
|
||||
}
|
||||
|
||||
private void managedProfileSetup(Context context, final PackageManager pm, Intent broadcast,
|
||||
@@ -161,4 +163,10 @@ public class SettingsInitialize extends BroadcastReceiver {
|
||||
pm.setComponentEnabledSetting(searchStateReceiver, enableState,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
|
||||
private void storeSuwCompleteTimestamp(Context context, Intent broadcast) {
|
||||
if (SetupWizardUtils.ACTION_SETUP_WIZARD_FINISHED.equals(broadcast.getAction())) {
|
||||
ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
49
src/com/android/settings/SettingsPreferenceBindingFactory.kt
Normal file
49
src/com/android/settings/SettingsPreferenceBindingFactory.kt
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 androidx.preference.Preference
|
||||
import com.android.settingslib.RestrictedPreferenceHelperProvider
|
||||
import com.android.settingslib.metadata.PreferenceHierarchyNode
|
||||
import com.android.settingslib.preference.DefaultPreferenceBindingFactory
|
||||
import com.android.settingslib.preference.PreferenceBinding
|
||||
|
||||
/** Preference binding factory for settings app. */
|
||||
class SettingsPreferenceBindingFactory : DefaultPreferenceBindingFactory() {
|
||||
override fun bind(
|
||||
preference: Preference,
|
||||
node: PreferenceHierarchyNode,
|
||||
preferenceBinding: PreferenceBinding?,
|
||||
) {
|
||||
super.bind(preference, node, preferenceBinding)
|
||||
|
||||
// handle restriction consistently
|
||||
val metadata = node.metadata
|
||||
if (metadata is PreferenceRestrictionMixin) {
|
||||
if (preference is RestrictedPreferenceHelperProvider) {
|
||||
preference.getRestrictedPreferenceHelper().apply {
|
||||
useAdminDisabledSummary(metadata.useAdminDisabledSummary)
|
||||
val context = preference.context
|
||||
val restrictionKeys = metadata.restrictionKeys
|
||||
if (!context.hasBaseUserRestriction(restrictionKeys)) {
|
||||
setDisabledByAdmin(context.getRestrictionEnforcedAdmin(restrictionKeys))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
|
||||
import static com.android.settingslib.media.PhoneMediaDevice.isDesktop;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
@@ -33,6 +36,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.annotation.XmlRes;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
@@ -45,12 +50,14 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.core.InstrumentedPreferenceFragment;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settings.support.actionbar.HelpResourceProvider;
|
||||
import com.android.settings.widget.HighlightablePreferenceGroupAdapter;
|
||||
import com.android.settings.widget.LoadingViewController;
|
||||
import com.android.settingslib.CustomDialogPreferenceCompat;
|
||||
import com.android.settingslib.CustomEditTextPreferenceCompat;
|
||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||
import com.android.settingslib.preference.PreferenceScreenCreator;
|
||||
import com.android.settingslib.search.Indexable;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
@@ -173,6 +180,31 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final int getPreferenceScreenResId(@NonNull Context context) {
|
||||
return getPreferenceScreenResId();
|
||||
}
|
||||
|
||||
/** Returns if catalyst is enabled on current screen. */
|
||||
public final boolean isCatalystEnabled() {
|
||||
// TODO(b/379130874): make Catalyst compatible with desktop device, such as user restriction
|
||||
// check.
|
||||
Context context = getContext();
|
||||
if (context != null && isDesktop(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getPreferenceScreenCreator() != null;
|
||||
}
|
||||
|
||||
protected @Nullable PreferenceScreenCreator getPreferenceScreenCreator() {
|
||||
if (!Flags.catalyst()) {
|
||||
return null;
|
||||
}
|
||||
Context context = getContext();
|
||||
return context != null ? getPreferenceScreenCreator(context) : null;
|
||||
}
|
||||
|
||||
public View setPinnedHeaderView(int layoutResId) {
|
||||
final LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
final View pinnedHeader =
|
||||
@@ -367,9 +399,13 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
|
||||
@Override
|
||||
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
|
||||
final Bundle arguments = getArguments();
|
||||
mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen,
|
||||
arguments == null
|
||||
? null : arguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY),
|
||||
String key = arguments == null ? null : arguments.getString(EXTRA_FRAGMENT_ARG_KEY);
|
||||
if (Flags.catalyst() && key == null) {
|
||||
Activity activity = getActivity();
|
||||
Intent intent = activity != null ? activity.getIntent() : null;
|
||||
key = intent != null ? intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY) : null;
|
||||
}
|
||||
mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen, key,
|
||||
mPreferenceHighlighted);
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
59
src/com/android/settings/SettingsService.kt
Normal file
59
src/com/android/settings/SettingsService.kt
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 android.content.Intent
|
||||
import com.android.settings.flags.Flags
|
||||
import com.android.settingslib.graph.PreferenceGetterRequest
|
||||
import com.android.settingslib.graph.PreferenceSetterRequest
|
||||
import com.android.settingslib.ipc.ApiPermissionChecker
|
||||
import com.android.settingslib.service.PreferenceService
|
||||
|
||||
/** Service to expose settings APIs. */
|
||||
class SettingsService :
|
||||
PreferenceService(
|
||||
graphPermissionChecker = ApiPermissionChecker.alwaysAllow(),
|
||||
setterPermissionChecker = SetterPermissionChecker(),
|
||||
getterPermissionChecker = GetterPermissionChecker(),
|
||||
) {
|
||||
|
||||
override fun onBind(intent: Intent) =
|
||||
if (Flags.catalystService()) super.onBind(intent) else null
|
||||
}
|
||||
|
||||
/** Permission checker for external setter API. */
|
||||
private class SetterPermissionChecker : ApiPermissionChecker<PreferenceSetterRequest> {
|
||||
|
||||
override fun hasPermission(
|
||||
application: Application,
|
||||
myUid: Int,
|
||||
callingUid: Int,
|
||||
request: PreferenceSetterRequest,
|
||||
) = true
|
||||
}
|
||||
|
||||
/** Permission checker for external getter API. */
|
||||
private class GetterPermissionChecker : ApiPermissionChecker<PreferenceGetterRequest> {
|
||||
|
||||
override fun hasPermission(
|
||||
application: Application,
|
||||
myUid: Int,
|
||||
callingUid: Int,
|
||||
request: PreferenceGetterRequest,
|
||||
) = true
|
||||
}
|
||||
@@ -32,6 +32,9 @@ import java.util.Arrays;
|
||||
|
||||
public class SetupWizardUtils {
|
||||
|
||||
public static final String ACTION_SETUP_WIZARD_FINISHED =
|
||||
"com.google.android.setupwizard.SETUP_WIZARD_FINISHED";
|
||||
|
||||
public static String getThemeString(Intent intent) {
|
||||
String theme = intent.getStringExtra(WizardManagerHelper.EXTRA_THEME);
|
||||
if (theme == null) {
|
||||
|
||||
@@ -291,23 +291,23 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
|
||||
// Certificates can be installed into SYSTEM_UID or WIFI_UID through CertInstaller.
|
||||
final int myUserId = UserHandle.myUserId();
|
||||
final int systemUid = UserHandle.getUid(myUserId, Process.SYSTEM_UID);
|
||||
final int wifiUid = UserHandle.getUid(myUserId, Process.WIFI_UID);
|
||||
|
||||
try {
|
||||
KeyStore processKeystore = KeyStore.getInstance(KEYSTORE_PROVIDER);
|
||||
processKeystore.load(null);
|
||||
KeyStore wifiKeystore = null;
|
||||
if (myUserId == 0) {
|
||||
wifiKeystore = KeyStore.getInstance(KEYSTORE_PROVIDER);
|
||||
wifiKeystore.load(new AndroidKeyStoreLoadStoreParameter(
|
||||
KeyProperties.NAMESPACE_WIFI));
|
||||
}
|
||||
|
||||
List<Credential> credentials = new ArrayList<>();
|
||||
credentials.addAll(getCredentialsForUid(processKeystore, systemUid).values());
|
||||
if (wifiKeystore != null) {
|
||||
credentials.addAll(getCredentialsForUid(wifiKeystore, wifiUid).values());
|
||||
|
||||
UserManager userManager = getContext().getSystemService(UserManager.class);
|
||||
if (userManager.isAdminUser()) {
|
||||
wifiKeystore = KeyStore.getInstance(KEYSTORE_PROVIDER);
|
||||
wifiKeystore.load(
|
||||
new AndroidKeyStoreLoadStoreParameter(KeyProperties.NAMESPACE_WIFI));
|
||||
credentials.addAll(
|
||||
getCredentialsForUid(wifiKeystore, Process.WIFI_UID).values());
|
||||
}
|
||||
|
||||
return credentials;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to load credentials from Keystore.", e);
|
||||
|
||||
@@ -131,6 +131,7 @@ import com.android.settings.password.ConfirmDeviceCredentialActivity;
|
||||
import com.android.settingslib.widget.ActionBarShadowController;
|
||||
import com.android.settingslib.widget.AdaptiveIcon;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -1180,9 +1181,9 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
try {
|
||||
return context.getPackageManager().getApplicationInfo(packageName, 0).enabled;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error while retrieving application info for package " + packageName, e);
|
||||
// Expected, package is not installed or not enabled.
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Get {@link Resources} by subscription id if subscription id is valid. */
|
||||
@@ -1329,8 +1330,7 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getHomepageIconColor(Context context) {
|
||||
return getColorAttrDefaultColor(
|
||||
context, com.android.internal.R.attr.materialColorOnSurface);
|
||||
return context.getColor(com.android.internal.R.color.materialColorOnSurface);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1516,13 +1516,13 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
final UserManager userManager = context.getSystemService(
|
||||
UserManager.class);
|
||||
final int status = biometricManager.canAuthenticate(getEffectiveUserId(
|
||||
userManager, userId), BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
|
||||
userManager, userId), BiometricManager.Authenticators.IDENTITY_CHECK);
|
||||
switch(status) {
|
||||
case BiometricManager.BIOMETRIC_SUCCESS:
|
||||
return BiometricStatus.OK;
|
||||
case BiometricManager.BIOMETRIC_ERROR_LOCKOUT:
|
||||
return BiometricStatus.LOCKOUT;
|
||||
case BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE:
|
||||
case BiometricManager.BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE:
|
||||
case BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS:
|
||||
return BiometricStatus.NOT_ACTIVE;
|
||||
default:
|
||||
@@ -1582,7 +1582,7 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
final Intent intent = new Intent();
|
||||
if (android.hardware.biometrics.Flags.mandatoryBiometrics()) {
|
||||
intent.putExtra(BIOMETRIC_PROMPT_AUTHENTICATORS,
|
||||
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
|
||||
BiometricManager.Authenticators.IDENTITY_CHECK);
|
||||
}
|
||||
intent.putExtra(BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT,
|
||||
resources.getString(R.string.cancel));
|
||||
@@ -1600,4 +1600,19 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
pm.setComponentEnabledSetting(componentName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the supplied package is a protected package. Otherwise, returns
|
||||
* {@code false}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param packageName the package name
|
||||
*/
|
||||
public static boolean isProtectedPackage(
|
||||
@NonNull Context context, @NonNull String packageName) {
|
||||
final List<String> protectedPackageNames = Arrays.asList(context.getResources()
|
||||
.getStringArray(com.android.internal.R.array
|
||||
.config_biometric_protected_package_names));
|
||||
return protectedPackageNames != null && protectedPackageNames.contains(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,18 @@ package com.android.settings.accessibility;
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.util.FeatureFlagUtils;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
/** Settings fragment containing bluetooth audio routing. */
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class AccessibilityAudioRoutingFragment extends RestrictedDashboardFragment {
|
||||
private static final String TAG = "AccessibilityAudioRoutingFragment";
|
||||
|
||||
@@ -47,6 +53,25 @@ public class AccessibilityAudioRoutingFragment extends RestrictedDashboardFragme
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isPageSearchEnabled(Context context) {
|
||||
if (!FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final HearingAidHelper mHelper = new HearingAidHelper(context);
|
||||
return mHelper.isHearingAidSupported();
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_audio_routing_fragment);
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_audio_routing_fragment) {
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
if (Flags.fixA11ySettingsSearch()) {
|
||||
return AccessibilityAudioRoutingFragment.isPageSearchEnabled(context);
|
||||
} else {
|
||||
return super.isPageSearchEnabled(context);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -49,9 +49,14 @@ public class AccessibilityButtonFooterPreferenceController extends
|
||||
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.
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_description
|
||||
: R.string.accessibility_button_description;
|
||||
final int titleResource;
|
||||
if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
|
||||
titleResource = R.string.accessibility_button_description;
|
||||
} else {
|
||||
titleResource = AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_description
|
||||
: R.string.accessibility_button_description;
|
||||
}
|
||||
final CharSequence footerText = Html.fromHtml(
|
||||
MessageFormat.format(mContext.getString(titleResource), 1, 2, 3),
|
||||
Html.FROM_HTML_MODE_COMPACT);
|
||||
|
||||
@@ -61,7 +61,12 @@ public class AccessibilityButtonPreferenceController extends BasePreferenceContr
|
||||
}
|
||||
|
||||
private int getPreferenceTitleResource() {
|
||||
return AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_title : R.string.accessibility_button_title;
|
||||
if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
|
||||
return R.string.accessibility_button_title;
|
||||
} else {
|
||||
return AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_title
|
||||
: R.string.accessibility_button_title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
|
||||
import com.android.internal.accessibility.AccessibilityShortcutController;
|
||||
@@ -118,6 +119,21 @@ public class AccessibilityHearingAidsFragment extends AccessibilityShortcutPrefe
|
||||
return getText(R.string.accessibility_hearing_device_shortcut_title);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isPageSearchEnabled(Context context) {
|
||||
final HearingAidHelper mHelper = new HearingAidHelper(context);
|
||||
return mHelper.isHearingAidSupported();
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_hearing_aids);
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_hearing_aids) {
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
if (Flags.fixA11ySettingsSearch()) {
|
||||
return AccessibilityHearingAidsFragment.isPageSearchEnabled(context);
|
||||
} else {
|
||||
return super.isPageSearchEnabled(context);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settingslib.PrimarySwitchPreference;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnCreate;
|
||||
import com.android.settingslib.core.lifecycle.events.OnDestroy;
|
||||
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||
|
||||
/** PrimarySwitchPreferenceController that shows quick settings tooltip on first use. */
|
||||
public abstract class AccessibilityQuickSettingsPrimarySwitchPreferenceController
|
||||
extends TogglePreferenceController
|
||||
implements LifecycleObserver, OnCreate, OnDestroy, OnSaveInstanceState {
|
||||
private static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
|
||||
private final Handler mHandler;
|
||||
private PrimarySwitchPreference mPreference;
|
||||
private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
|
||||
private boolean mNeedsQSTooltipReshow = false;
|
||||
|
||||
/** Returns the accessibility tile component name. */
|
||||
@Nullable
|
||||
abstract ComponentName getTileComponentName();
|
||||
|
||||
/** Returns the accessibility tile tooltip content. */
|
||||
abstract CharSequence getTileTooltipContent();
|
||||
|
||||
public AccessibilityQuickSettingsPrimarySwitchPreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mHandler = new Handler(context.getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// Restore the tooltip.
|
||||
if (savedInstanceState != null) {
|
||||
if (savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_RESHOW)) {
|
||||
mNeedsQSTooltipReshow = savedInstanceState.getBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
final boolean isTooltipWindowShowing = mTooltipWindow != null && mTooltipWindow.isShowing();
|
||||
if (isTooltipWindowShowing) {
|
||||
mTooltipWindow.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
final boolean isTooltipWindowShowing = mTooltipWindow != null && mTooltipWindow.isShowing();
|
||||
if (mNeedsQSTooltipReshow || isTooltipWindowShowing) {
|
||||
outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreference = screen.findPreference(getPreferenceKey());
|
||||
if (mNeedsQSTooltipReshow) {
|
||||
mHandler.post(this::showQuickSettingsTooltipIfNeeded);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
if (isChecked) {
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
return isChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
private void showQuickSettingsTooltipIfNeeded() {
|
||||
if (mPreference == null) {
|
||||
// Returns if no preference found by slice highlight menu.
|
||||
return;
|
||||
}
|
||||
|
||||
final ComponentName tileComponentName = getTileComponentName();
|
||||
if (tileComponentName == null) {
|
||||
// Returns if no tile service assigned.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
|
||||
mContext, tileComponentName)) {
|
||||
// Returns if quick settings tooltip only show once.
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO (287728819): Move tooltip showing to SystemUI
|
||||
// Since the lifecycle of controller is independent of that of the preference, doing
|
||||
// null check on switch is a temporary solution for the case that switch view
|
||||
// is not ready when we would like to show the tooltip. If the switch is not ready,
|
||||
// we give up showing the tooltip and also do not reshow it in the future.
|
||||
if (mPreference.getSwitch() != null) {
|
||||
mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(mContext);
|
||||
mTooltipWindow.setup(getTileTooltipContent(),
|
||||
R.drawable.accessibility_auto_added_qs_tooltip_illustration);
|
||||
mTooltipWindow.showAtTopCenter(mPreference.getSwitch());
|
||||
}
|
||||
AccessibilityQuickSettingUtils.optInValueToSharedPreferences(mContext, tileComponentName);
|
||||
mNeedsQSTooltipReshow = false;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.InputDevice;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -44,7 +43,6 @@ import com.android.internal.content.PackageMonitor;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.inputmethod.PhysicalKeyboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
@@ -72,14 +70,12 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
private static final String CATEGORY_DISPLAY = "display_category";
|
||||
@VisibleForTesting
|
||||
static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
|
||||
private static final String CATEGORY_KEYBOARD_OPTIONS = "physical_keyboard_options_category";
|
||||
@VisibleForTesting
|
||||
static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
|
||||
|
||||
private static final String[] CATEGORIES = new String[]{
|
||||
CATEGORY_SCREEN_READER, CATEGORY_CAPTIONS, CATEGORY_AUDIO, CATEGORY_DISPLAY,
|
||||
CATEGORY_SPEECH, CATEGORY_INTERACTION_CONTROL,
|
||||
CATEGORY_KEYBOARD_OPTIONS, CATEGORY_DOWNLOADED_SERVICES
|
||||
CATEGORY_SPEECH, CATEGORY_INTERACTION_CONTROL, CATEGORY_DOWNLOADED_SERVICES
|
||||
};
|
||||
|
||||
// Extras passed to sub-fragments.
|
||||
@@ -181,9 +177,7 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
// Observe changes from accessibility selection menu
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
}
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_STICKY_KEYS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SLOW_KEYS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS);
|
||||
@@ -272,7 +266,7 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
* @return The service summary
|
||||
*/
|
||||
public static CharSequence getServiceSummary(Context context, AccessibilityServiceInfo info,
|
||||
boolean serviceEnabled) {
|
||||
boolean serviceEnabled) {
|
||||
if (serviceEnabled && info.crashed) {
|
||||
return context.getText(R.string.accessibility_summary_state_stopped);
|
||||
}
|
||||
@@ -413,10 +407,8 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
final List<RestrictedPreference> preferenceList = getInstalledAccessibilityPreferences(
|
||||
getPrefContext(), installedShortcutList, installedServiceList);
|
||||
|
||||
if (Flags.checkPrebundledIsPreinstalled()) {
|
||||
removeNonPreinstalledComponents(mPreBundledServiceComponentToCategoryMap,
|
||||
installedShortcutList, installedServiceList);
|
||||
}
|
||||
removeNonPreinstalledComponents(mPreBundledServiceComponentToCategoryMap,
|
||||
installedShortcutList, installedServiceList);
|
||||
|
||||
final PreferenceCategory downloadedServicesCategory =
|
||||
mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);
|
||||
@@ -458,7 +450,6 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
// Hide category if it is empty.
|
||||
updatePreferenceCategoryVisibility(CATEGORY_SCREEN_READER);
|
||||
updatePreferenceCategoryVisibility(CATEGORY_SPEECH);
|
||||
updatePreferenceCategoryVisibility(CATEGORY_KEYBOARD_OPTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -548,9 +539,7 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
/**
|
||||
* Updates preferences related to system configurations.
|
||||
*/
|
||||
protected void updateSystemPreferences() {
|
||||
updateKeyboardPreferencesVisibility();
|
||||
}
|
||||
protected void updateSystemPreferences() {}
|
||||
|
||||
private void updatePreferencesState() {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
@@ -559,53 +548,6 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
findPreference(controller.getPreferenceKey())));
|
||||
}
|
||||
|
||||
private void updateKeyboardPreferencesVisibility() {
|
||||
if (!mCategoryToPrefCategoryMap.containsKey(CATEGORY_KEYBOARD_OPTIONS)) {
|
||||
return;
|
||||
}
|
||||
boolean isVisible = isAnyHardKeyboardsExist()
|
||||
&& isAnyKeyboardPreferenceAvailable();
|
||||
mCategoryToPrefCategoryMap.get(CATEGORY_KEYBOARD_OPTIONS).setVisible(
|
||||
isVisible);
|
||||
if (isVisible) {
|
||||
//set summary here.
|
||||
findPreference(KeyboardBounceKeyPreferenceController.PREF_KEY).setSummary(
|
||||
getContext().getString(R.string.bounce_keys_summary,
|
||||
PhysicalKeyboardFragment.BOUNCE_KEYS_THRESHOLD));
|
||||
findPreference(KeyboardSlowKeyPreferenceController.PREF_KEY).setSummary(
|
||||
getContext().getString(R.string.slow_keys_summary,
|
||||
PhysicalKeyboardFragment.SLOW_KEYS_THRESHOLD));
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isAnyHardKeyboardsExist() {
|
||||
for (int deviceId : InputDevice.getDeviceIds()) {
|
||||
final InputDevice device = InputDevice.getDevice(deviceId);
|
||||
if (device != null && !device.isVirtual() && device.isFullKeyboard()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAnyKeyboardPreferenceAvailable() {
|
||||
for (List<AbstractPreferenceController> controllerList : getPreferenceControllers()) {
|
||||
for (AbstractPreferenceController controller : controllerList) {
|
||||
if (controller.getPreferenceKey().equals(
|
||||
KeyboardBounceKeyPreferenceController.PREF_KEY)
|
||||
|| controller.getPreferenceKey().equals(
|
||||
KeyboardSlowKeyPreferenceController.PREF_KEY)
|
||||
|| controller.getPreferenceKey().equals(
|
||||
KeyboardStickyKeyPreferenceController.PREF_KEY)) {
|
||||
if (controller.isAvailable()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_settings) {
|
||||
@Override
|
||||
@@ -663,10 +605,12 @@ public class AccessibilitySettings extends DashboardFragment implements
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onInputDeviceAdded(int deviceId) {}
|
||||
public void onInputDeviceAdded(int deviceId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputDeviceRemoved(int deviceId) {}
|
||||
public void onInputDeviceRemoved(int deviceId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputDeviceChanged(int deviceId) {
|
||||
|
||||
@@ -41,8 +41,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.display.AutoBrightnessPreferenceController;
|
||||
import com.android.settings.display.BrightnessLevelPreferenceController;
|
||||
import com.android.settings.display.BrightnessLevelPreferenceControllerForSetupWizard;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
@@ -168,16 +167,10 @@ public class AccessibilitySettingsForSetupWizard extends DashboardFragment
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
// Requires lifecycle, so added programmatically (normally via resId).
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
BrightnessLevelPreferenceController brightnessLevelPreferenceController =
|
||||
new BrightnessLevelPreferenceController(context, getSettingsLifecycle());
|
||||
brightnessLevelPreferenceController.setInSetupWizard(true);
|
||||
controllers.add(brightnessLevelPreferenceController);
|
||||
String autoBrightnessKey = context.getString(R.string.preference_key_auto_brightness);
|
||||
AutoBrightnessPreferenceController autoBrightnessPreferenceController =
|
||||
new AutoBrightnessPreferenceController(context, autoBrightnessKey);
|
||||
autoBrightnessPreferenceController.setInSetupWizard(true);
|
||||
controllers.add(autoBrightnessPreferenceController);
|
||||
controllers.add(new BrightnessLevelPreferenceControllerForSetupWizard(
|
||||
context, getSettingsLifecycle()));
|
||||
return controllers;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,24 +17,21 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
|
||||
import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.getShortcutSummaryList;
|
||||
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_GENERAL_CATEGORY;
|
||||
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_SAVED_QS_TOOLTIP_TYPE;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.icu.text.CaseMap;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -46,18 +43,16 @@ import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
|
||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for accessibility fragments shortcut functions and dialog management.
|
||||
@@ -120,9 +115,7 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
|
||||
final List<String> shortcutFeatureKeys = new ArrayList<>();
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
}
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
mSettingsContentObserver = new AccessibilitySettingsContentObserver(new Handler());
|
||||
mSettingsContentObserver.registerKeysToObserverCallback(shortcutFeatureKeys, key -> {
|
||||
updateShortcutPreferenceData();
|
||||
@@ -241,6 +234,7 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public void onToggleClicked(ShortcutPreference preference) {
|
||||
if (getComponentName() == null) {
|
||||
@@ -248,13 +242,12 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
|
||||
}
|
||||
|
||||
final int shortcutTypes = getUserPreferredShortcutTypes();
|
||||
if (preference.isChecked()) {
|
||||
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
|
||||
getComponentName());
|
||||
final boolean isChecked = preference.isChecked();
|
||||
getPrefContext().getSystemService(AccessibilityManager.class).enableShortcutsForTargets(
|
||||
isChecked, shortcutTypes,
|
||||
Set.of(getComponentName().flattenToString()), getPrefContext().getUserId());
|
||||
if (isChecked) {
|
||||
showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
|
||||
} else {
|
||||
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes,
|
||||
getComponentName());
|
||||
}
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
}
|
||||
@@ -340,37 +333,7 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
|
||||
}
|
||||
|
||||
final int shortcutTypes = getUserPreferredShortcutTypes();
|
||||
|
||||
// LINT.IfChange(shortcut_type_ui_order)
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if (hasShortcutType(shortcutTypes, QUICK_SETTINGS)) {
|
||||
final CharSequence qsTitle = context.getText(
|
||||
R.string.accessibility_feature_shortcut_setting_summary_quick_settings);
|
||||
list.add(qsTitle);
|
||||
}
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, SOFTWARE)) {
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, HARDWARE)) {
|
||||
final CharSequence hardwareTitle = context.getText(
|
||||
R.string.accessibility_shortcut_hardware_keyword);
|
||||
list.add(hardwareTitle);
|
||||
}
|
||||
// LINT.ThenChange(/res/xml/accessibility_edit_shortcuts.xml:shortcut_type_ui_order)
|
||||
|
||||
// Show software shortcut if first time to use.
|
||||
if (list.isEmpty()) {
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
|
||||
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
|
||||
null, LocaleUtils.getConcatenatedString(list));
|
||||
}
|
||||
|
||||
private boolean hasShortcutType(int value, @UserShortcutType int type) {
|
||||
return (value & type) == type;
|
||||
return getShortcutSummaryList(context, shortcutTypes);
|
||||
}
|
||||
|
||||
protected void updateShortcutPreferenceData() {
|
||||
@@ -410,38 +373,13 @@ public abstract class AccessibilityShortcutPreferenceFragment extends Restricted
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated made obsolete by quick settings rollout.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
private void showQuickSettingsTooltipIfNeeded() {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
// Don't show Quick Settings tooltip
|
||||
return;
|
||||
}
|
||||
final ComponentName tileComponentName = getTileComponentName();
|
||||
if (tileComponentName == null) {
|
||||
// Returns if no tile service assigned.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
|
||||
getContext(), tileComponentName)) {
|
||||
// Returns if quick settings tooltip only show once.
|
||||
return;
|
||||
}
|
||||
|
||||
final CharSequence content = getTileTooltipContent(mNeedsQSTooltipType);
|
||||
if (TextUtils.isEmpty(content)) {
|
||||
// Returns if no content of tile tooltip assigned.
|
||||
return;
|
||||
}
|
||||
|
||||
final int imageResId = mNeedsQSTooltipType == QuickSettingsTooltipType.GUIDE_TO_EDIT
|
||||
? R.drawable.accessibility_qs_tooltip_illustration
|
||||
: R.drawable.accessibility_auto_added_qs_tooltip_illustration;
|
||||
mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(getContext());
|
||||
mTooltipWindow.setup(content, imageResId);
|
||||
mTooltipWindow.showAtTopCenter(getView());
|
||||
AccessibilityQuickSettingUtils.optInValueToSharedPreferences(getContext(),
|
||||
tileComponentName);
|
||||
mNeedsQSTooltipReshow = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,15 +16,19 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
|
||||
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -60,14 +64,14 @@ import androidx.core.widget.TextViewCompat;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.android.server.accessibility.Flags;
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
|
||||
import com.android.internal.accessibility.util.ShortcutUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settingslib.utils.StringUtil;
|
||||
import com.android.settingslib.widget.LottieColorUtils;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.airbnb.lottie.LottieDrawable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -330,7 +334,8 @@ public final class AccessibilityShortcutsTutorial {
|
||||
result -> Log.w(TAG, "Invalid image raw resource id: " + imageRawRes,
|
||||
result));
|
||||
lottieView.setAnimation(imageRawRes);
|
||||
lottieView.setRepeatCount(LottieDrawable.INFINITE);
|
||||
// Follow the Motion Stoppable requirement by using a finite animation.
|
||||
lottieView.setRepeatCount(0);
|
||||
LottieColorUtils.applyDynamicColors(context, lottieView);
|
||||
lottieView.playAnimation();
|
||||
|
||||
@@ -396,95 +401,84 @@ public final class AccessibilityShortcutsTutorial {
|
||||
return textView;
|
||||
}
|
||||
|
||||
private static TutorialPage createSoftwareTutorialPage(@NonNull Context context) {
|
||||
final int type = SOFTWARE;
|
||||
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);
|
||||
indicatorIcon.setEnabled(false);
|
||||
|
||||
return new TutorialPage(type, title, image, indicatorIcon, instruction);
|
||||
@SuppressLint("SwitchIntDef")
|
||||
private static CharSequence getShortcutTitle(
|
||||
@NonNull Context context, @UserShortcutType int shortcutType, int buttonMode) {
|
||||
return switch (shortcutType) {
|
||||
case HARDWARE -> context.getText(R.string.accessibility_tutorial_dialog_title_volume);
|
||||
case SOFTWARE -> getSoftwareTitle(context, buttonMode);
|
||||
case GESTURE -> context.getText(R.string.accessibility_tutorial_dialog_title_gesture);
|
||||
case TRIPLETAP -> context.getText(R.string.accessibility_tutorial_dialog_title_triple);
|
||||
case TWOFINGER_DOUBLETAP -> context.getString(
|
||||
R.string.accessibility_tutorial_dialog_title_two_finger_double, 2);
|
||||
case QUICK_SETTINGS -> context.getText(
|
||||
R.string.accessibility_tutorial_dialog_title_quick_setting);
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
private static TutorialPage createHardwareTutorialPage(@NonNull Context context) {
|
||||
final int type = HARDWARE;
|
||||
final CharSequence title =
|
||||
context.getText(R.string.accessibility_tutorial_dialog_title_volume);
|
||||
final View image =
|
||||
createIllustrationView(context, R.drawable.accessibility_shortcut_type_volume_keys);
|
||||
final ImageView indicatorIcon =
|
||||
createImageView(context, R.drawable.ic_accessibility_page_indicator);
|
||||
final CharSequence instruction =
|
||||
context.getText(R.string.accessibility_tutorial_dialog_message_volume);
|
||||
indicatorIcon.setEnabled(false);
|
||||
|
||||
return new TutorialPage(type, title, image, indicatorIcon, instruction);
|
||||
}
|
||||
|
||||
private static TutorialPage createTripleTapTutorialPage(@NonNull Context context) {
|
||||
final int type = TRIPLETAP;
|
||||
final CharSequence title =
|
||||
context.getText(R.string.accessibility_tutorial_dialog_title_triple);
|
||||
final View image =
|
||||
createIllustrationViewWithImageRawResource(context,
|
||||
R.raw.accessibility_shortcut_type_tripletap);
|
||||
final CharSequence instruction = context.getString(
|
||||
R.string.accessibility_tutorial_dialog_tripletap_instruction, 3);
|
||||
final ImageView indicatorIcon =
|
||||
createImageView(context, R.drawable.ic_accessibility_page_indicator);
|
||||
indicatorIcon.setEnabled(false);
|
||||
|
||||
return new TutorialPage(type, title, image, indicatorIcon, instruction);
|
||||
}
|
||||
|
||||
private static TutorialPage createTwoFingerTripleTapTutorialPage(@NonNull Context context) {
|
||||
final int type = TWOFINGER_DOUBLETAP;
|
||||
final int numFingers = 2;
|
||||
final CharSequence title = context.getString(
|
||||
R.string.accessibility_tutorial_dialog_title_two_finger_double, numFingers);
|
||||
final View image =
|
||||
createIllustrationViewWithImageRawResource(context,
|
||||
R.raw.accessibility_shortcut_type_2finger_doubletap);
|
||||
final CharSequence instruction = context.getString(
|
||||
R.string.accessibility_tutorial_dialog_twofinger_doubletap_instruction, numFingers);
|
||||
final ImageView indicatorIcon =
|
||||
createImageView(context, R.drawable.ic_accessibility_page_indicator);
|
||||
indicatorIcon.setEnabled(false);
|
||||
|
||||
return new TutorialPage(type, title, image, indicatorIcon, instruction);
|
||||
}
|
||||
|
||||
private static TutorialPage createQuickSettingsTutorialPage(
|
||||
@NonNull Context context, @NonNull CharSequence featureName, boolean inSetupWizard) {
|
||||
final int type = QUICK_SETTINGS;
|
||||
final CharSequence title =
|
||||
context.getText(R.string.accessibility_tutorial_dialog_title_quick_setting);
|
||||
final View image =
|
||||
createIllustrationView(context,
|
||||
@SuppressLint("SwitchIntDef")
|
||||
private static View getShortcutImage(
|
||||
@NonNull Context context, @UserShortcutType int shortcutType, int buttonMode) {
|
||||
return switch (shortcutType) {
|
||||
case HARDWARE -> createIllustrationView(
|
||||
context, R.drawable.accessibility_shortcut_type_volume_keys);
|
||||
case SOFTWARE -> createSoftwareImage(context, buttonMode);
|
||||
case GESTURE -> createIllustrationView(context,
|
||||
AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.drawable.accessibility_shortcut_type_gesture_touch_explore_on
|
||||
: R.drawable.accessibility_shortcut_type_gesture);
|
||||
case TRIPLETAP -> createIllustrationViewWithImageRawResource(context,
|
||||
R.raw.accessibility_shortcut_type_tripletap);
|
||||
case TWOFINGER_DOUBLETAP -> createIllustrationViewWithImageRawResource(context,
|
||||
R.raw.accessibility_shortcut_type_2finger_doubletap);
|
||||
case QUICK_SETTINGS -> {
|
||||
View v = createIllustrationView(context,
|
||||
R.drawable.accessibility_shortcut_type_quick_settings);
|
||||
// Remove the unneeded background, since the main image already includes a background
|
||||
image.findViewById(R.id.image_background).setVisibility(GONE);
|
||||
final int numFingers = AccessibilityUtil.isTouchExploreEnabled(context) ? 2 : 1;
|
||||
Map<String, Object> arguments = new ArrayMap<>();
|
||||
arguments.put("count", numFingers);
|
||||
arguments.put("featureName", featureName);
|
||||
final CharSequence instruction = StringUtil.getIcuPluralsString(context,
|
||||
arguments,
|
||||
R.string.accessibility_tutorial_dialog_message_quick_setting);
|
||||
final SpannableStringBuilder tutorialText = new SpannableStringBuilder();
|
||||
if (inSetupWizard) {
|
||||
tutorialText.append(context.getText(
|
||||
R.string.accessibility_tutorial_dialog_shortcut_unavailable_in_suw))
|
||||
.append("\n\n");
|
||||
}
|
||||
tutorialText.append(instruction);
|
||||
View bg = v.findViewById(R.id.image_background);
|
||||
if (bg != null) {
|
||||
bg.setVisibility(GONE);
|
||||
}
|
||||
yield v;
|
||||
}
|
||||
default -> new View(context);
|
||||
};
|
||||
}
|
||||
|
||||
private static CharSequence getShortcutInstruction(
|
||||
@NonNull Context context, @UserShortcutType int shortcutType, int buttonMode,
|
||||
@NonNull CharSequence featureName, boolean inSetupWizard) {
|
||||
return switch (shortcutType) {
|
||||
case HARDWARE -> context.getText(R.string.accessibility_tutorial_dialog_message_volume);
|
||||
case SOFTWARE -> getSoftwareInstruction(context, buttonMode);
|
||||
case GESTURE -> StringUtil.getIcuPluralsString(
|
||||
context,
|
||||
AccessibilityUtil.isTouchExploreEnabled(context) ? 3 : 2,
|
||||
R.string.accessibility_tutorial_dialog_gesture_shortcut_instruction);
|
||||
case TRIPLETAP -> context.getString(
|
||||
R.string.accessibility_tutorial_dialog_tripletap_instruction, 3);
|
||||
case TWOFINGER_DOUBLETAP -> context.getString(
|
||||
R.string.accessibility_tutorial_dialog_twofinger_doubletap_instruction, 2);
|
||||
case QUICK_SETTINGS -> getQuickSettingsInstruction(context, featureName, inSetupWizard);
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressLint("SwitchIntDef")
|
||||
private static TutorialPage createShortcutTutorialPage(
|
||||
@NonNull Context context, @UserShortcutType int shortcutType, int buttonMode,
|
||||
@NonNull CharSequence featureName, boolean inSetupWizard) {
|
||||
|
||||
final ImageView indicatorIcon =
|
||||
createImageView(context, R.drawable.ic_accessibility_page_indicator);
|
||||
indicatorIcon.setEnabled(false);
|
||||
|
||||
return new TutorialPage(type, title, image, indicatorIcon, tutorialText);
|
||||
return new TutorialPage(shortcutType,
|
||||
getShortcutTitle(context, shortcutType, buttonMode),
|
||||
getShortcutImage(context, shortcutType, buttonMode),
|
||||
createImageView(context, R.drawable.ic_accessibility_page_indicator),
|
||||
getShortcutInstruction(
|
||||
context, shortcutType, buttonMode, featureName, inSetupWizard));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,81 +489,54 @@ public final class AccessibilityShortcutsTutorial {
|
||||
static List<TutorialPage> createShortcutTutorialPages(
|
||||
@NonNull Context context, int shortcutTypes, @NonNull CharSequence featureName,
|
||||
boolean inSetupWizard) {
|
||||
// LINT.IfChange(shortcut_type_ui_order)
|
||||
final List<TutorialPage> tutorialPages = new ArrayList<>();
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if ((shortcutTypes & QUICK_SETTINGS)
|
||||
== QUICK_SETTINGS) {
|
||||
tutorialPages.add(
|
||||
createQuickSettingsTutorialPage(context, featureName, inSetupWizard));
|
||||
int buttonMode = ShortcutUtils.getButtonMode(context, context.getUserId());
|
||||
|
||||
for (int shortcutType: AccessibilityUtil.SHORTCUTS_ORDER_IN_UI) {
|
||||
if ((shortcutTypes & shortcutType) == 0) {
|
||||
continue;
|
||||
}
|
||||
tutorialPages.add(
|
||||
createShortcutTutorialPage(
|
||||
context, shortcutType, buttonMode, featureName, inSetupWizard));
|
||||
}
|
||||
if ((shortcutTypes & SOFTWARE) == SOFTWARE) {
|
||||
tutorialPages.add(createSoftwareTutorialPage(context));
|
||||
}
|
||||
|
||||
if ((shortcutTypes & HARDWARE) == HARDWARE) {
|
||||
tutorialPages.add(createHardwareTutorialPage(context));
|
||||
}
|
||||
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if ((shortcutTypes & TWOFINGER_DOUBLETAP)
|
||||
== TWOFINGER_DOUBLETAP) {
|
||||
tutorialPages.add(createTwoFingerTripleTapTutorialPage(context));
|
||||
}
|
||||
}
|
||||
|
||||
if ((shortcutTypes & TRIPLETAP) == TRIPLETAP) {
|
||||
tutorialPages.add(createTripleTapTutorialPage(context));
|
||||
}
|
||||
// LINT.ThenChange(/res/xml/accessibility_edit_shortcuts.xml:shortcut_type_ui_order)
|
||||
|
||||
return tutorialPages;
|
||||
}
|
||||
|
||||
private static View createSoftwareImage(Context context) {
|
||||
int resId;
|
||||
if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
|
||||
return createIllustrationViewWithImageRawResource(
|
||||
context, R.raw.accessibility_shortcut_type_fab);
|
||||
} else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
|
||||
resId = AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.drawable.accessibility_shortcut_type_gesture_touch_explore_on
|
||||
: R.drawable.accessibility_shortcut_type_gesture;
|
||||
} else {
|
||||
resId = R.drawable.accessibility_shortcut_type_navbar;
|
||||
}
|
||||
return createIllustrationView(context, resId);
|
||||
private static View createSoftwareImage(Context context, int buttonMode) {
|
||||
return switch(buttonMode) {
|
||||
case ACCESSIBILITY_BUTTON_MODE_GESTURE ->
|
||||
createIllustrationView(context,
|
||||
AccessibilityUtil.isTouchExploreEnabled(context)
|
||||
? R.drawable
|
||||
.accessibility_shortcut_type_gesture_touch_explore_on
|
||||
: R.drawable.accessibility_shortcut_type_gesture);
|
||||
case ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU ->
|
||||
createIllustrationViewWithImageRawResource(
|
||||
context, R.raw.accessibility_shortcut_type_fab);
|
||||
default -> createIllustrationView(
|
||||
context, R.drawable.accessibility_shortcut_type_navbar);
|
||||
};
|
||||
}
|
||||
|
||||
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 getSoftwareTitle(Context context, int buttonMode) {
|
||||
return context.getText(buttonMode == ACCESSIBILITY_BUTTON_MODE_GESTURE
|
||||
? R.string.accessibility_tutorial_dialog_title_gesture
|
||||
: R.string.accessibility_tutorial_dialog_title_button);
|
||||
}
|
||||
|
||||
private static CharSequence getSoftwareInstruction(Context context) {
|
||||
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 numFingers = AccessibilityUtil.isTouchExploreEnabled(context) ? 3 : 2;
|
||||
sb.append(StringUtil.getIcuPluralsString(
|
||||
private static CharSequence getSoftwareInstruction(Context context, int buttonMode) {
|
||||
return switch(buttonMode) {
|
||||
case ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU -> context.getText(
|
||||
R.string.accessibility_tutorial_dialog_message_floating_button);
|
||||
case ACCESSIBILITY_BUTTON_MODE_GESTURE -> StringUtil.getIcuPluralsString(
|
||||
context,
|
||||
numFingers,
|
||||
R.string.accessibility_tutorial_dialog_gesture_shortcut_instruction));
|
||||
} else {
|
||||
final int resId = R.string.accessibility_tutorial_dialog_message_button;
|
||||
sb.append(getSoftwareInstructionWithIcon(context, context.getText(resId)));
|
||||
}
|
||||
return sb;
|
||||
AccessibilityUtil.isTouchExploreEnabled(context) ? 3 : 2,
|
||||
R.string.accessibility_tutorial_dialog_gesture_shortcut_instruction);
|
||||
default -> getSoftwareInstructionWithIcon(context,
|
||||
context.getText(R.string.accessibility_tutorial_dialog_message_button));
|
||||
};
|
||||
}
|
||||
|
||||
private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) {
|
||||
@@ -590,6 +557,24 @@ public final class AccessibilityShortcutsTutorial {
|
||||
return spannableInstruction;
|
||||
}
|
||||
|
||||
private static CharSequence getQuickSettingsInstruction(
|
||||
Context context, CharSequence featureName, boolean inSetupWizard) {
|
||||
Map<String, Object> arguments = new ArrayMap<>();
|
||||
arguments.put("count",
|
||||
AccessibilityUtil.isTouchExploreEnabled(context) ? 2 : 1);
|
||||
arguments.put("featureName", featureName);
|
||||
final CharSequence pluralsString = StringUtil.getIcuPluralsString(
|
||||
context, arguments,
|
||||
R.string.accessibility_tutorial_dialog_message_quick_setting);
|
||||
final SpannableStringBuilder tutorialText = new SpannableStringBuilder();
|
||||
if (inSetupWizard) {
|
||||
tutorialText.append(context.getText(R.string
|
||||
.accessibility_tutorial_dialog_shortcut_unavailable_in_suw))
|
||||
.append("\n\n");
|
||||
}
|
||||
return tutorialText.append(pluralsString);
|
||||
}
|
||||
|
||||
private static class TutorialPage {
|
||||
private final int mType;
|
||||
private final CharSequence mTitle;
|
||||
|
||||
@@ -22,10 +22,12 @@ import static android.view.WindowInsets.Type.systemBars;
|
||||
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
|
||||
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.ComponentName;
|
||||
@@ -33,6 +35,7 @@ import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.icu.text.CaseMap;
|
||||
import android.os.Build;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
@@ -49,14 +52,27 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
|
||||
import com.android.internal.accessibility.util.ShortcutUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/** Provides utility methods to accessibility settings only. */
|
||||
public final class AccessibilityUtil {
|
||||
// LINT.IfChange(shortcut_type_ui_order)
|
||||
static final int[] SHORTCUTS_ORDER_IN_UI = {
|
||||
QUICK_SETTINGS,
|
||||
SOFTWARE, // FAB displays before gesture. Navbar displays without gesture.
|
||||
GESTURE,
|
||||
HARDWARE,
|
||||
TWOFINGER_DOUBLETAP,
|
||||
TRIPLETAP
|
||||
};
|
||||
// LINT.ThenChange(/res/xml/accessibility_edit_shortcuts.xml:shortcut_type_ui_order)
|
||||
|
||||
private AccessibilityUtil(){}
|
||||
|
||||
@@ -139,8 +155,8 @@ public final class AccessibilityUtil {
|
||||
|
||||
/** Determines if a gesture navigation bar is being used. */
|
||||
public static boolean isGestureNavigateEnabled(Context context) {
|
||||
return context.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_navBarInteractionMode)
|
||||
return Settings.Secure.getInt(context.getContentResolver(),
|
||||
Settings.Secure.NAVIGATION_MODE, -1)
|
||||
== NAV_BAR_MODE_GESTURAL;
|
||||
}
|
||||
|
||||
@@ -178,153 +194,6 @@ public final class AccessibilityUtil {
|
||||
: AccessibilityServiceFragmentType.TOGGLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opts in component name into multiple {@code shortcutTypes} colon-separated string in
|
||||
* Settings.
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param shortcutTypes A combination of {@link UserShortcutType}.
|
||||
* @param componentName The component name that need to be opted in Settings.
|
||||
*/
|
||||
static void optInAllValuesToSettings(Context context, int shortcutTypes,
|
||||
@NonNull ComponentName componentName) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ true,
|
||||
shortcutTypes,
|
||||
Set.of(componentName.flattenToString()),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((shortcutTypes & SOFTWARE) == SOFTWARE) {
|
||||
optInValueToSettings(context, SOFTWARE, componentName);
|
||||
}
|
||||
if (((shortcutTypes & HARDWARE) == HARDWARE)) {
|
||||
optInValueToSettings(context, HARDWARE, componentName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opts in component name into {@code shortcutType} colon-separated string in Settings.
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param shortcutType The preferred shortcut type user selected.
|
||||
* @param componentName The component name that need to be opted in Settings.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static void optInValueToSettings(Context context, @UserShortcutType int shortcutType,
|
||||
@NonNull ComponentName componentName) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ true,
|
||||
shortcutType,
|
||||
Set.of(componentName.flattenToString()),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final String targetKey = convertKeyFromSettings(shortcutType);
|
||||
final String targetString = Settings.Secure.getString(context.getContentResolver(),
|
||||
targetKey);
|
||||
|
||||
if (hasValueInSettings(context, shortcutType, componentName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
|
||||
if (!TextUtils.isEmpty(targetString)) {
|
||||
joiner.add(targetString);
|
||||
}
|
||||
joiner.add(componentName.flattenToString());
|
||||
|
||||
Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Opts out component name into multiple {@code shortcutTypes} colon-separated string in
|
||||
* Settings.
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param shortcutTypes A combination of {@link UserShortcutType}.
|
||||
* @param componentName The component name that need to be opted out from Settings.
|
||||
*/
|
||||
static void optOutAllValuesFromSettings(Context context, int shortcutTypes,
|
||||
@NonNull ComponentName componentName) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ false,
|
||||
shortcutTypes,
|
||||
Set.of(componentName.flattenToString()),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((shortcutTypes & SOFTWARE) == SOFTWARE) {
|
||||
optOutValueFromSettings(context, SOFTWARE, componentName);
|
||||
}
|
||||
if (((shortcutTypes & HARDWARE) == HARDWARE)) {
|
||||
optOutValueFromSettings(context, HARDWARE, componentName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opts out component name into {@code shortcutType} colon-separated string in Settings.
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param shortcutType The preferred shortcut type user selected.
|
||||
* @param componentName The component name that need to be opted out from Settings.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static void optOutValueFromSettings(Context context, @UserShortcutType int shortcutType,
|
||||
@NonNull ComponentName componentName) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ false,
|
||||
shortcutType,
|
||||
Set.of(componentName.flattenToString()),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
|
||||
final String targetKey = convertKeyFromSettings(shortcutType);
|
||||
final String targetString = Settings.Secure.getString(context.getContentResolver(),
|
||||
targetKey);
|
||||
|
||||
if (TextUtils.isEmpty(targetString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sStringColonSplitter.setString(targetString);
|
||||
while (sStringColonSplitter.hasNext()) {
|
||||
final String name = sStringColonSplitter.next();
|
||||
if (TextUtils.isEmpty(name) || (componentName.flattenToString()).equals(name)) {
|
||||
continue;
|
||||
}
|
||||
joiner.add(name);
|
||||
}
|
||||
|
||||
Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if component name existed in one of {@code shortcutTypes} string in Settings.
|
||||
*
|
||||
@@ -335,22 +204,18 @@ public final class AccessibilityUtil {
|
||||
*/
|
||||
static boolean hasValuesInSettings(Context context, int shortcutTypes,
|
||||
@NonNull ComponentName componentName) {
|
||||
boolean exist = false;
|
||||
if ((shortcutTypes & SOFTWARE) == SOFTWARE) {
|
||||
exist = hasValueInSettings(context, SOFTWARE, componentName);
|
||||
}
|
||||
if (((shortcutTypes & HARDWARE) == HARDWARE)) {
|
||||
exist |= hasValueInSettings(context, HARDWARE, componentName);
|
||||
}
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if ((shortcutTypes & QUICK_SETTINGS)
|
||||
== QUICK_SETTINGS) {
|
||||
exist |= hasValueInSettings(context, QUICK_SETTINGS,
|
||||
componentName);
|
||||
for (int shortcutType : AccessibilityUtil.SHORTCUTS_ORDER_IN_UI) {
|
||||
if (!android.provider.Flags.a11yStandaloneGestureEnabled()) {
|
||||
if ((shortcutType & GESTURE) == GESTURE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((shortcutTypes & shortcutType) == shortcutType
|
||||
&& hasValueInSettings(context, shortcutType, componentName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return exist;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -360,33 +225,19 @@ public final class AccessibilityUtil {
|
||||
* @param shortcutType The preferred shortcut type user selected.
|
||||
* @param componentName The component name that need to be checked existed in Settings.
|
||||
* @return {@code true} if componentName existed in Settings.
|
||||
*
|
||||
* @deprecated use
|
||||
* {@link ShortcutUtils#isShortcutContained(Context, int, String)} instead.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
@VisibleForTesting
|
||||
static boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType,
|
||||
@NonNull ComponentName componentName) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
return ShortcutUtils.getShortcutTargetsFromSettings(
|
||||
context, shortcutType, UserHandle.myUserId()
|
||||
).contains(componentName.flattenToString());
|
||||
}
|
||||
|
||||
final String targetKey = convertKeyFromSettings(shortcutType);
|
||||
final String targetString = Settings.Secure.getString(context.getContentResolver(),
|
||||
targetKey);
|
||||
|
||||
if (TextUtils.isEmpty(targetString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sStringColonSplitter.setString(targetString);
|
||||
|
||||
while (sStringColonSplitter.hasNext()) {
|
||||
final String name = sStringColonSplitter.next();
|
||||
if ((componentName.flattenToString()).equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ShortcutUtils.getShortcutTargetsFromSettings(
|
||||
context, shortcutType, UserHandle.myUserId()
|
||||
).contains(componentName.flattenToString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,15 +251,14 @@ public final class AccessibilityUtil {
|
||||
static int getUserShortcutTypesFromSettings(Context context,
|
||||
@NonNull ComponentName componentName) {
|
||||
int shortcutTypes = DEFAULT;
|
||||
if (hasValuesInSettings(context, SOFTWARE, componentName)) {
|
||||
shortcutTypes |= SOFTWARE;
|
||||
}
|
||||
if (hasValuesInSettings(context, HARDWARE, componentName)) {
|
||||
shortcutTypes |= HARDWARE;
|
||||
}
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if (hasValuesInSettings(context, QUICK_SETTINGS, componentName)) {
|
||||
shortcutTypes |= QUICK_SETTINGS;
|
||||
for (int shortcutType : AccessibilityUtil.SHORTCUTS_ORDER_IN_UI) {
|
||||
if (!android.provider.Flags.a11yStandaloneGestureEnabled()) {
|
||||
if ((shortcutType & GESTURE) == GESTURE) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (hasValueInSettings(context, shortcutType, componentName)) {
|
||||
shortcutTypes |= shortcutType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,23 +270,15 @@ public final class AccessibilityUtil {
|
||||
*
|
||||
* @param shortcutType The shortcut type.
|
||||
* @return Mapping key in Settings.
|
||||
*
|
||||
* @deprecated use
|
||||
* {@link ShortcutUtils#convertToKey(int)} instead.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
static String convertKeyFromSettings(@UserShortcutType int shortcutType) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
return ShortcutUtils.convertToKey(shortcutType);
|
||||
}
|
||||
|
||||
switch (shortcutType) {
|
||||
case SOFTWARE:
|
||||
return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
|
||||
case HARDWARE:
|
||||
return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
|
||||
case TRIPLETAP:
|
||||
return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported userShortcutType " + shortcutType);
|
||||
}
|
||||
return ShortcutUtils.convertToKey(shortcutType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -505,4 +347,60 @@ public final class AccessibilityUtil {
|
||||
Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, /*
|
||||
true */ 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles a localized string describing the provided shortcut types.
|
||||
*/
|
||||
public static CharSequence getShortcutSummaryList(Context context, int shortcutTypes) {
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
|
||||
for (int shortcutType : AccessibilityUtil.SHORTCUTS_ORDER_IN_UI) {
|
||||
if (!android.provider.Flags.a11yStandaloneGestureEnabled()
|
||||
&& (shortcutType & GESTURE) == GESTURE) {
|
||||
continue;
|
||||
}
|
||||
if (!com.android.server.accessibility.Flags
|
||||
.enableMagnificationMultipleFingerMultipleTapGesture()
|
||||
&& (shortcutType & TWOFINGER_DOUBLETAP) == TWOFINGER_DOUBLETAP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((shortcutTypes & shortcutType) == shortcutType) {
|
||||
list.add(switch (shortcutType) {
|
||||
case QUICK_SETTINGS -> context.getText(
|
||||
R.string.accessibility_feature_shortcut_setting_summary_quick_settings);
|
||||
case SOFTWARE -> getSoftwareShortcutSummary(context);
|
||||
case GESTURE -> context.getText(
|
||||
R.string.accessibility_shortcut_edit_summary_software_gesture);
|
||||
case HARDWARE -> context.getText(
|
||||
R.string.accessibility_shortcut_hardware_keyword);
|
||||
case TWOFINGER_DOUBLETAP -> context.getString(
|
||||
R.string.accessibility_shortcut_two_finger_double_tap_keyword, 2);
|
||||
case TRIPLETAP -> context.getText(
|
||||
R.string.accessibility_shortcut_triple_tap_keyword);
|
||||
default -> "";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
list.sort(CharSequence::compare);
|
||||
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
|
||||
null, LocaleUtils.getConcatenatedString(list));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static CharSequence getSoftwareShortcutSummary(Context context) {
|
||||
if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
|
||||
return context.getText(R.string.accessibility_shortcut_edit_summary_software);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 android.app.Activity.RESULT_CANCELED;
|
||||
|
||||
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.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.display.AutoBrightnessSettings;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
|
||||
/**
|
||||
* Fragment for adaptive brightness settings in the SetupWizard.
|
||||
*/
|
||||
public class AutoBrightnessPreferenceFragmentForSetupWizard extends AutoBrightnessSettings {
|
||||
|
||||
private static final String FOOTER_PREFERENCE_KEY = "auto_brightness_footer";
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
updateFooterContentDescription();
|
||||
|
||||
if (view instanceof GlifPreferenceLayout) {
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
|
||||
final String title = getContext().getString(
|
||||
R.string.auto_brightness_title);
|
||||
final Drawable icon = getContext().getDrawable(R.drawable.ic_accessibility_visibility);
|
||||
icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.colorPrimary));
|
||||
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
|
||||
/* description= */ null, icon);
|
||||
|
||||
final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
|
||||
AccessibilitySetupWizardUtils.setPrimaryButton(getContext(), mixin, R.string.done,
|
||||
() -> {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView onCreateRecyclerView(@NonNull LayoutInflater inflater,
|
||||
@NonNull ViewGroup parent, @Nullable Bundle savedInstanceState) {
|
||||
if (parent instanceof GlifPreferenceLayout) {
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
|
||||
return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||
}
|
||||
return super.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.SUW_ACCESSIBILITY_AUTO_BRIGHTNESS;
|
||||
}
|
||||
|
||||
private void updateFooterContentDescription() {
|
||||
final PreferenceScreen screen = getPreferenceScreen();
|
||||
final FooterPreference footerPreference = screen.findPreference(FOOTER_PREFERENCE_KEY);
|
||||
if (footerPreference != null) {
|
||||
String title = getString(R.string.auto_brightness_content_description_title);
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(title).append("\n\n").append(footerPreference.getTitle());
|
||||
footerPreference.setContentDescription(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,11 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.PluralsRes;
|
||||
import android.annotation.StringRes;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.utils.StringUtil;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -52,16 +45,6 @@ public final class AutoclickUtils {
|
||||
*/
|
||||
static final int AUTOCLICK_DELAY_STEP = 100;
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({
|
||||
Quantity.ONE,
|
||||
Quantity.FEW
|
||||
})
|
||||
private @interface Quantity {
|
||||
int ONE = 1;
|
||||
int FEW = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets string that should be used for provided autoclick delay.
|
||||
*
|
||||
@@ -73,13 +56,12 @@ public final class AutoclickUtils {
|
||||
*/
|
||||
public static CharSequence getAutoclickDelaySummary(Context context,
|
||||
@StringRes int id, int delayMillis) {
|
||||
final int quantity = (delayMillis == 1000) ? Quantity.ONE : Quantity.FEW;
|
||||
final float delaySecond = (float) delayMillis / 1000;
|
||||
// Only show integer when delay time is 1.
|
||||
final String decimalFormat = (delaySecond == 1) ? "%.0f" : "%.1f";
|
||||
|
||||
Map<String, Object> arguments = new HashMap<>();
|
||||
arguments.put("count", quantity);
|
||||
arguments.put("count", delaySecond);
|
||||
arguments.put("time", String.format(decimalFormat, delaySecond));
|
||||
return StringUtil.getIcuPluralsString(context, arguments, id);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,14 @@ package com.android.settings.accessibility;
|
||||
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
|
||||
import com.android.settings.connecteddevice.DevicePreferenceCallback;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
@@ -32,6 +35,9 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
import com.android.settingslib.search.SearchIndexableRaw;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Controller to update the {@link androidx.preference.PreferenceCategory} for all
|
||||
@@ -44,6 +50,7 @@ public class AvailableHearingDevicePreferenceController extends
|
||||
BluetoothCallback {
|
||||
|
||||
private static final String TAG = "AvailableHearingDevicePreferenceController";
|
||||
private static final String SEARCH_DATA_KEY_PREFIX = "a11y_available_hearing_device";
|
||||
|
||||
private BluetoothDeviceUpdater mAvailableHearingDeviceUpdater;
|
||||
private final LocalBluetoothManager mLocalBluetoothManager;
|
||||
@@ -56,6 +63,14 @@ public class AvailableHearingDevicePreferenceController extends
|
||||
context);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void init(AvailableHearingDeviceUpdater availableHearingDeviceUpdater) {
|
||||
if (mAvailableHearingDeviceUpdater != null) {
|
||||
throw new IllegalStateException("Should not call init() more than 1 time.");
|
||||
}
|
||||
mAvailableHearingDeviceUpdater = availableHearingDeviceUpdater;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes objects in this controller. Need to call this before onStart().
|
||||
*
|
||||
@@ -107,4 +122,34 @@ public class AvailableHearingDevicePreferenceController extends
|
||||
getMetricsCategory());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
||||
if (Flags.fixA11ySettingsSearch()) {
|
||||
if (mLocalBluetoothManager == null) {
|
||||
Log.d(TAG, "Bluetooth is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
for (CachedBluetoothDevice cachedDevice :
|
||||
mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()) {
|
||||
|
||||
if (!AvailableHearingDeviceUpdater.isAvailableHearingDevice(cachedDevice)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||
// Include the identity address and add prefix to ensure the key is unique and
|
||||
// distinguish from Bluetooth's connected devices.
|
||||
data.key = SEARCH_DATA_KEY_PREFIX
|
||||
+ cachedDevice.getName() + cachedDevice.getIdentityAddress();
|
||||
data.title = cachedDevice.getName();
|
||||
data.summaryOn = mContext.getString(R.string.accessibility_hearingaid_title);
|
||||
data.screenTitle = mContext.getString(R.string.accessibility_hearingaid_title);
|
||||
rawData.add(data);
|
||||
}
|
||||
} else {
|
||||
super.updateDynamicRawDataToIndex(rawData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
|
||||
@@ -34,10 +35,16 @@ public class AvailableHearingDeviceUpdater extends AvailableMediaBluetoothDevice
|
||||
super(context, devicePreferenceCallback, metricsCategory);
|
||||
}
|
||||
|
||||
static boolean isAvailableHearingDevice(CachedBluetoothDevice cachedDevice) {
|
||||
final BluetoothDevice device = cachedDevice.getDevice();
|
||||
return cachedDevice.isHearingAidDevice()
|
||||
&& device.getBondState() == BluetoothDevice.BOND_BONDED
|
||||
&& device.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
|
||||
return cachedDevice.isHearingAidDevice()
|
||||
&& isDeviceConnected(cachedDevice)
|
||||
return isAvailableHearingDevice(cachedDevice)
|
||||
&& isDeviceInCachedDevicesList(cachedDevice);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ public class BalanceSeekBar extends SeekBar {
|
||||
Settings.System.MASTER_BALANCE, balance, UserHandle.USER_CURRENT);
|
||||
}
|
||||
final int max = getMax();
|
||||
if (Flags.audioBalanceStateDescription() && max > 0) {
|
||||
if (max > 0) {
|
||||
seekBar.setStateDescription(createStateDescription(mContext,
|
||||
R.string.audio_seek_bar_state_left_first,
|
||||
R.string.audio_seek_bar_state_right_first,
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 com.android.settings.core.BasePreferenceController;
|
||||
|
||||
public class BaseCaptioningCustomController extends BasePreferenceController {
|
||||
protected final CaptionHelper mCaptionHelper;
|
||||
|
||||
public BaseCaptioningCustomController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mCaptionHelper.getCustomCaptionAvailability();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -211,4 +213,14 @@ public class CaptionHelper {
|
||||
public Locale getLocale() {
|
||||
return mCaptioningManager.getLocale();
|
||||
}
|
||||
|
||||
/** Returns availability for custom caption preferences, depending on current user style. */
|
||||
public int getCustomCaptionAvailability() {
|
||||
if (com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) {
|
||||
return (getRawUserStyle() == CaptionStyle.PRESET_CUSTOM)
|
||||
? AVAILABLE : AVAILABLE_UNSEARCHABLE;
|
||||
} else {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,15 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning background color. */
|
||||
public class CaptioningBackgroundColorController extends BasePreferenceController
|
||||
public class CaptioningBackgroundColorController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
private int mCachedNonDefaultOpacity = CaptionStyle.COLOR_UNSPECIFIED;
|
||||
|
||||
public CaptioningBackgroundColorController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,22 +23,13 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning background opacity. */
|
||||
public class CaptioningBackgroundOpacityController extends BasePreferenceController
|
||||
public class CaptioningBackgroundOpacityController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
|
||||
public CaptioningBackgroundOpacityController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
@@ -27,7 +28,6 @@ import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
@@ -36,11 +36,11 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** Preference controller for captioning custom visibility. */
|
||||
public class CaptioningCustomController extends BasePreferenceController
|
||||
public class CaptioningCustomController extends BaseCaptioningCustomController
|
||||
implements LifecycleObserver, OnStart, OnStop {
|
||||
|
||||
@Nullable
|
||||
private Preference mCustom;
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
private final ContentResolver mContentResolver;
|
||||
@VisibleForTesting
|
||||
AccessibilitySettingsContentObserver mSettingsContentObserver;
|
||||
@@ -50,32 +50,31 @@ public class CaptioningCustomController extends BasePreferenceController
|
||||
);
|
||||
|
||||
public CaptioningCustomController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
mContentResolver = context.getContentResolver();
|
||||
mSettingsContentObserver = new AccessibilitySettingsContentObserver(
|
||||
new Handler(Looper.getMainLooper()));
|
||||
mSettingsContentObserver.registerKeysToObserverCallback(CAPTIONING_FEATURE_KEYS,
|
||||
key -> refreshShowingCustom());
|
||||
this(context, preferenceKey,
|
||||
new AccessibilitySettingsContentObserver(new Handler(Looper.getMainLooper())));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
CaptioningCustomController(Context context, String preferenceKey,
|
||||
CaptioningCustomController(
|
||||
Context context, String preferenceKey,
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
this(context, preferenceKey);
|
||||
super(context, preferenceKey);
|
||||
mContentResolver = context.getContentResolver();
|
||||
mSettingsContentObserver = contentObserver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
mSettingsContentObserver.registerKeysToObserverCallback(CAPTIONING_FEATURE_KEYS, key -> {
|
||||
if (mCustom != null) {
|
||||
mCustom.setVisible(shouldShowPreference());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mCustom = screen.findPreference(getPreferenceKey());
|
||||
refreshShowingCustom();
|
||||
if (mCustom != null) {
|
||||
mCustom.setVisible(shouldShowPreference());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,9 +87,7 @@ public class CaptioningCustomController extends BasePreferenceController
|
||||
mSettingsContentObserver.unregister(mContentResolver);
|
||||
}
|
||||
|
||||
private void refreshShowingCustom() {
|
||||
final boolean isCustomPreset =
|
||||
mCaptionHelper.getRawUserStyle() == CaptioningManager.CaptionStyle.PRESET_CUSTOM;
|
||||
mCustom.setVisible(isCustomPreset);
|
||||
private boolean shouldShowPreference() {
|
||||
return mCaptionHelper.getRawUserStyle() == CaptioningManager.CaptionStyle.PRESET_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,22 +23,13 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning edge color. */
|
||||
public class CaptioningEdgeColorController extends BasePreferenceController
|
||||
public class CaptioningEdgeColorController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
|
||||
public CaptioningEdgeColorController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,22 +21,13 @@ import android.content.Context;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning edge type. */
|
||||
public class CaptioningEdgeTypeController extends BasePreferenceController
|
||||
public class CaptioningEdgeTypeController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
|
||||
public CaptioningEdgeTypeController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,23 +24,15 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning foreground color. */
|
||||
public class CaptioningForegroundColorController extends BasePreferenceController
|
||||
public class CaptioningForegroundColorController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
private int mCachedNonDefaultOpacity = CaptionStyle.COLOR_UNSPECIFIED;
|
||||
|
||||
public CaptioningForegroundColorController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,22 +23,13 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning foreground opacity. */
|
||||
public class CaptioningForegroundOpacityController extends BasePreferenceController
|
||||
public class CaptioningForegroundOpacityController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
|
||||
public CaptioningForegroundOpacityController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,22 +23,12 @@ import android.view.accessibility.CaptioningManager.CaptionStyle;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning type face. */
|
||||
public class CaptioningTypefaceController extends BasePreferenceController
|
||||
public class CaptioningTypefaceController extends BaseCaptioningCustomController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
|
||||
public CaptioningTypefaceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,23 +25,15 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning window color. */
|
||||
public class CaptioningWindowColorController extends BasePreferenceController
|
||||
public class CaptioningWindowColorController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
private int mCachedNonDefaultOpacity = CaptionStyle.COLOR_UNSPECIFIED;
|
||||
|
||||
public CaptioningWindowColorController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,22 +23,13 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.ListDialogPreference.OnValueChangedListener;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Preference controller for captioning window opacity. */
|
||||
public class CaptioningWindowOpacityController extends BasePreferenceController
|
||||
public class CaptioningWindowOpacityController extends BaseCaptioningCustomController
|
||||
implements OnValueChangedListener {
|
||||
|
||||
private final CaptionHelper mCaptionHelper;
|
||||
|
||||
public CaptioningWindowOpacityController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptionHelper = new CaptionHelper(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.ColorDisplayManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.Flags;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
@@ -47,7 +50,6 @@ public class ColorAndMotionFragment extends DashboardFragment {
|
||||
|
||||
// Preferences
|
||||
private static final String DISPLAY_DALTONIZER_PREFERENCE_SCREEN = "daltonizer_preference";
|
||||
private static final String TOGGLE_DISABLE_ANIMATIONS = "toggle_disable_animations";
|
||||
private static final String TOGGLE_LARGE_POINTER_ICON = "toggle_large_pointer_icon";
|
||||
@VisibleForTesting
|
||||
static final String TOGGLE_FORCE_INVERT = "toggle_force_invert";
|
||||
@@ -74,9 +76,7 @@ public class ColorAndMotionFragment extends DashboardFragment {
|
||||
mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
|
||||
mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
}
|
||||
mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
if (Flags.forceInvertColor()) {
|
||||
mShortcutFeatureKeys.add(ToggleForceInvertPreferenceController.SETTINGS_KEY);
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class ColorAndMotionFragment extends DashboardFragment {
|
||||
mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN);
|
||||
|
||||
// Disable animation.
|
||||
mToggleDisableAnimationsPreference = findPreference(TOGGLE_DISABLE_ANIMATIONS);
|
||||
mToggleDisableAnimationsPreference = findPreference(RemoveAnimationsPreference.KEY);
|
||||
|
||||
// Large pointer icon.
|
||||
mToggleLargePointerIconPreference = findPreference(TOGGLE_LARGE_POINTER_ICON);
|
||||
@@ -148,6 +148,12 @@ public class ColorAndMotionFragment extends DashboardFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPreferenceScreenBindingKey(@NonNull Context context) {
|
||||
return ColorAndMotionScreen.KEY;
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_color_and_motion);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 com.android.settings.R
|
||||
import com.android.settings.Settings.ColorAndMotionActivity
|
||||
import com.android.settings.flags.Flags
|
||||
import com.android.settings.utils.makeLaunchIntent
|
||||
import com.android.settingslib.metadata.PreferenceMetadata
|
||||
import com.android.settingslib.metadata.ProvidePreferenceScreen
|
||||
import com.android.settingslib.metadata.preferenceHierarchy
|
||||
import com.android.settingslib.preference.PreferenceScreenCreator
|
||||
|
||||
@ProvidePreferenceScreen
|
||||
class ColorAndMotionScreen : PreferenceScreenCreator {
|
||||
override val key: String
|
||||
get() = KEY
|
||||
|
||||
override val title: Int
|
||||
get() = R.string.accessibility_color_and_motion_title
|
||||
|
||||
override val icon: Int
|
||||
get() = R.drawable.ic_color_and_motion
|
||||
|
||||
override fun isFlagEnabled(context: Context) = Flags.catalystAccessibilityColorAndMotion()
|
||||
|
||||
override fun hasCompleteHierarchy(): Boolean = false
|
||||
|
||||
override fun fragmentClass() = ColorAndMotionFragment::class.java
|
||||
|
||||
override fun getPreferenceHierarchy(context: Context) =
|
||||
preferenceHierarchy(this) {
|
||||
+RemoveAnimationsPreference()
|
||||
}
|
||||
|
||||
override fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?) =
|
||||
makeLaunchIntent(context, ColorAndMotionActivity::class.java, metadata?.key)
|
||||
|
||||
companion object {
|
||||
const val KEY = "accessibility_color_and_motion"
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
// LINT.IfChange
|
||||
/** A toggle preference controller for disable animations. */
|
||||
public class DisableAnimationsPreferenceController extends TogglePreferenceController implements
|
||||
LifecycleObserver, OnStart, OnStop {
|
||||
@@ -123,3 +124,4 @@ public class DisableAnimationsPreferenceController extends TogglePreferenceContr
|
||||
mContentResolver.unregisterContentObserver(mSettingsContentObserver);
|
||||
}
|
||||
}
|
||||
// LINT.ThenChange(src/com/android/settings/accessibility/RemoveAnimationsPreference.kt)
|
||||
@@ -35,7 +35,7 @@ class DisplaySizeData extends PreviewSizeData<Integer> {
|
||||
super(context);
|
||||
|
||||
mDensity = new DisplayDensityUtils(getContext());
|
||||
final int initialIndex = mDensity.getCurrentIndexForDefaultDisplay();
|
||||
final int initialIndex = mDensity.getCurrentIndex();
|
||||
if (initialIndex < 0) {
|
||||
// Failed to obtain default density, which means we failed to
|
||||
// connect to the window manager service. Just use the current
|
||||
@@ -46,9 +46,9 @@ class DisplaySizeData extends PreviewSizeData<Integer> {
|
||||
setInitialIndex(0);
|
||||
setValues(Collections.singletonList(densityDpi));
|
||||
} else {
|
||||
setDefaultValue(mDensity.getDefaultDensityForDefaultDisplay());
|
||||
setDefaultValue(mDensity.getDefaultDensity());
|
||||
setInitialIndex(initialIndex);
|
||||
setValues(Arrays.stream(mDensity.getDefaultDisplayDensityValues()).boxed()
|
||||
setValues(Arrays.stream(mDensity.getValues()).boxed()
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ package com.android.settings.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
|
||||
/**
|
||||
* Fragment that does not have toggle bar to turn on service to use.
|
||||
*
|
||||
@@ -37,29 +35,4 @@ public class InvisibleToggleAccessibilityServicePreferenceFragment extends
|
||||
super.onInstallSwitchPreferenceToggleSwitch();
|
||||
mToggleServiceSwitchPreference.setVisible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Enables accessibility service only when user had allowed permission. Disables
|
||||
* accessibility service when shortcutPreference is unchecked.
|
||||
*/
|
||||
@Override
|
||||
public void onToggleClicked(ShortcutPreference preference) {
|
||||
super.onToggleClicked(preference);
|
||||
boolean enabled = getArguments().getBoolean(AccessibilitySettings.EXTRA_CHECKED)
|
||||
&& preference.isChecked();
|
||||
AccessibilityUtils.setAccessibilityServiceState(getContext(), mComponentName, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Enables accessibility service when user clicks permission allow button.
|
||||
*/
|
||||
@Override
|
||||
void onAllowButtonFromShortcutToggleClicked() {
|
||||
super.onAllowButtonFromShortcutToggleClicked();
|
||||
AccessibilityUtils.setAccessibilityServiceState(getContext(), mComponentName, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.hardware.input.InputSettings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.inputmethod.PhysicalKeyboardFragment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A toggle preference controller for keyboard bounce key.
|
||||
*/
|
||||
public class KeyboardBounceKeyPreferenceController extends TogglePreferenceController {
|
||||
private static final String TAG = "BounceKeyPrefController";
|
||||
static final String PREF_KEY = "toggle_keyboard_bounce_keys";
|
||||
|
||||
public KeyboardBounceKeyPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return InputSettings.isAccessibilityBounceKeysFeatureEnabled()
|
||||
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return InputSettings.isAccessibilityBounceKeysEnabled(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
InputSettings.setAccessibilityBounceKeysThreshold(mContext,
|
||||
isChecked ? PhysicalKeyboardFragment.BOUNCE_KEYS_THRESHOLD
|
||||
: 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNonIndexableKeys(@NonNull List<String> keys) {
|
||||
super.updateNonIndexableKeys(keys);
|
||||
|
||||
if (Flags.fixA11ySettingsSearch() && !AccessibilitySettings.isAnyHardKeyboardsExist()) {
|
||||
if (keys.contains(getPreferenceKey())) {
|
||||
Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list.");
|
||||
return;
|
||||
}
|
||||
keys.add(getPreferenceKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.hardware.input.InputSettings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.inputmethod.PhysicalKeyboardFragment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A toggle preference controller for keyboard slow key.
|
||||
*/
|
||||
public class KeyboardSlowKeyPreferenceController extends TogglePreferenceController {
|
||||
private static final String TAG = "SlowKeyPrefController";
|
||||
|
||||
static final String PREF_KEY = "toggle_keyboard_slow_keys";
|
||||
|
||||
public KeyboardSlowKeyPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return InputSettings.isAccessibilitySlowKeysFeatureFlagEnabled()
|
||||
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return InputSettings.isAccessibilitySlowKeysEnabled(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
InputSettings.setAccessibilitySlowKeysThreshold(mContext,
|
||||
isChecked ? PhysicalKeyboardFragment.SLOW_KEYS_THRESHOLD
|
||||
: 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNonIndexableKeys(@NonNull List<String> keys) {
|
||||
super.updateNonIndexableKeys(keys);
|
||||
|
||||
if (Flags.fixA11ySettingsSearch() && !AccessibilitySettings.isAnyHardKeyboardsExist()) {
|
||||
if (keys.contains(getPreferenceKey())) {
|
||||
Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list.");
|
||||
return;
|
||||
}
|
||||
keys.add(getPreferenceKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.hardware.input.InputSettings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A toggle preference controller for keyboard sticky key.
|
||||
*/
|
||||
public class KeyboardStickyKeyPreferenceController extends TogglePreferenceController {
|
||||
private static final String TAG = "StickyKeyPrefController";
|
||||
static final String PREF_KEY = "toggle_keyboard_sticky_keys";
|
||||
|
||||
public KeyboardStickyKeyPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return InputSettings.isAccessibilityStickyKeysFeatureEnabled()
|
||||
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return InputSettings.isAccessibilityStickyKeysEnabled(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
InputSettings.setAccessibilityStickyKeysEnabled(mContext, isChecked);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNonIndexableKeys(@NonNull List<String> keys) {
|
||||
super.updateNonIndexableKeys(keys);
|
||||
|
||||
if (Flags.fixA11ySettingsSearch() && !AccessibilitySettings.isAnyHardKeyboardsExist()) {
|
||||
if (keys.contains(getPreferenceKey())) {
|
||||
Log.w(TAG, "Skipping updateNonIndexableKeys, key already in list.");
|
||||
return;
|
||||
}
|
||||
keys.add(getPreferenceKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
initLaunchPreference();
|
||||
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
removePreference(KEY_USE_SERVICE_PREFERENCE);
|
||||
removePreference(getUseServicePreferenceKey());
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
super.onProcessArguments(arguments);
|
||||
mComponentName = arguments.getParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME);
|
||||
final ActivityInfo info = getAccessibilityShortcutInfo().getActivityInfo();
|
||||
mPackageName = info.loadLabel(getPackageManager()).toString();
|
||||
mFeatureName = info.loadLabel(getPackageManager());
|
||||
|
||||
// Settings animated image.
|
||||
final int animatedImageRes = arguments.getInt(
|
||||
|
||||
@@ -24,6 +24,7 @@ import static com.android.settings.accessibility.AccessibilityUtil.getScreenWidt
|
||||
import static com.google.common.primitives.Ints.max;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Paint.FontMetrics;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.util.AttributeSet;
|
||||
@@ -39,6 +40,7 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.Utils;
|
||||
|
||||
import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
@@ -128,6 +130,8 @@ public final class PaletteListPreference extends Preference {
|
||||
final List<Integer> paletteColors = getPaletteColors(context);
|
||||
final List<String> paletteData = getPaletteData(context);
|
||||
|
||||
final ColorStateList textColor =
|
||||
Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
|
||||
final float textPadding =
|
||||
context.getResources().getDimension(R.dimen.accessibility_layout_margin_start_end);
|
||||
final String maxLengthData =
|
||||
@@ -143,6 +147,7 @@ public final class PaletteListPreference extends Preference {
|
||||
for (int i = 0; i < paletteData.size(); ++i) {
|
||||
final TextView textView = new TextView(context);
|
||||
textView.setText(paletteData.get(i));
|
||||
textView.setTextColor(textColor);
|
||||
textView.setHeight(paletteItemHeight);
|
||||
textView.setPaddingRelative(Math.round(textPadding), 0, 0, 0);
|
||||
textView.setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
|
||||
|
||||
import android.content.ComponentName;
|
||||
@@ -25,12 +24,10 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.accessibility.Flags;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
|
||||
import com.android.internal.accessibility.util.ShortcutUtils;
|
||||
|
||||
@@ -123,12 +120,7 @@ public final class PreferredShortcuts {
|
||||
public static void updatePreferredShortcutsFromSettings(
|
||||
@NonNull Context context, @NonNull Set<String> components) {
|
||||
final Map<Integer, Set<String>> shortcutTypeToTargets = new ArrayMap<>();
|
||||
for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
|
||||
if (!Flags.a11yQsShortcut()
|
||||
&& shortcutType == QUICK_SETTINGS) {
|
||||
// Skip saving quick setting as preferred shortcut option when flag is not enabled
|
||||
continue;
|
||||
}
|
||||
for (int shortcutType : AccessibilityUtil.SHORTCUTS_ORDER_IN_UI) {
|
||||
shortcutTypeToTargets.put(
|
||||
shortcutType,
|
||||
ShortcutUtils.getShortcutTargetsFromSettings(
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.display.ColorDisplayManager;
|
||||
@@ -29,12 +26,12 @@ import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.server.display.feature.flags.Flags;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settingslib.PrimarySwitchPreference;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
@@ -42,7 +39,7 @@ import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
|
||||
/** PreferenceController that shows the Reduce Bright Colors summary */
|
||||
public class ReduceBrightColorsPreferenceController
|
||||
extends AccessibilityQuickSettingsPrimarySwitchPreferenceController
|
||||
extends TogglePreferenceController
|
||||
implements LifecycleObserver, OnStart, OnStop {
|
||||
private ContentObserver mSettingsContentObserver;
|
||||
private PrimarySwitchPreference mPreference;
|
||||
@@ -72,7 +69,6 @@ public class ReduceBrightColorsPreferenceController
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
super.setChecked(isChecked);
|
||||
return mColorDisplayManager.setReduceBrightColorsActivated(isChecked);
|
||||
}
|
||||
|
||||
@@ -125,20 +121,4 @@ public class ReduceBrightColorsPreferenceController
|
||||
public void onStop() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mSettingsContentObserver);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected ComponentName getTileComponentName() {
|
||||
// TODO: When clean up the feature flag, change the parent class from
|
||||
// AccessibilityQuickSettingsPrimarySwitchPreferenceController to
|
||||
// TogglePreferenceController
|
||||
return android.view.accessibility.Flags.a11yQsShortcut()
|
||||
? null : REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
CharSequence getTileTooltipContent() {
|
||||
return mContext.getText(
|
||||
R.string.accessibility_reduce_bright_colors_auto_added_qs_tooltip_content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.annotation.DrawableRes
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import com.android.settings.R
|
||||
import com.android.settingslib.datastore.HandlerExecutor
|
||||
import com.android.settingslib.datastore.KeyValueStore
|
||||
import com.android.settingslib.datastore.KeyedObserver
|
||||
import com.android.settingslib.datastore.NoOpKeyedObservable
|
||||
import com.android.settingslib.datastore.SettingsGlobalStore
|
||||
import com.android.settingslib.metadata.PreferenceLifecycleContext
|
||||
import com.android.settingslib.metadata.PreferenceLifecycleProvider
|
||||
import com.android.settingslib.metadata.ReadWritePermit
|
||||
import com.android.settingslib.metadata.SensitivityLevel
|
||||
import com.android.settingslib.metadata.SwitchPreference
|
||||
|
||||
class RemoveAnimationsPreference :
|
||||
SwitchPreference(
|
||||
KEY,
|
||||
R.string.accessibility_disable_animations,
|
||||
R.string.accessibility_disable_animations_summary,
|
||||
),
|
||||
PreferenceLifecycleProvider {
|
||||
|
||||
private var mSettingsKeyedObserver: KeyedObserver<String>? = null
|
||||
|
||||
override val icon: Int
|
||||
@DrawableRes get() = R.drawable.ic_accessibility_animation
|
||||
|
||||
override fun onStart(context: PreferenceLifecycleContext) {
|
||||
val observer = KeyedObserver<String> { _, _ -> context.notifyPreferenceChange(KEY) }
|
||||
mSettingsKeyedObserver = observer
|
||||
val storage = SettingsGlobalStore.get(context)
|
||||
for (key in getAnimationKeys()) {
|
||||
storage.addObserver(key, observer, HandlerExecutor.main)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop(context: PreferenceLifecycleContext) {
|
||||
mSettingsKeyedObserver?.let {
|
||||
val storage = SettingsGlobalStore.get(context)
|
||||
for (key in getAnimationKeys()) {
|
||||
storage.removeObserver(key, it)
|
||||
}
|
||||
mSettingsKeyedObserver = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun storage(context: Context): KeyValueStore = RemoveAnimationsStorage(context)
|
||||
|
||||
override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) =
|
||||
ReadWritePermit.ALLOW
|
||||
|
||||
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
|
||||
ReadWritePermit.ALLOW
|
||||
|
||||
override val sensitivityLevel
|
||||
get() = SensitivityLevel.NO_SENSITIVITY
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private class RemoveAnimationsStorage(private val context: Context) :
|
||||
NoOpKeyedObservable<String>(), KeyValueStore {
|
||||
override fun contains(key: String) = key == KEY
|
||||
|
||||
override fun <T : Any> getValue(key: String, valueType: Class<T>) =
|
||||
when {
|
||||
key == KEY && valueType == Boolean::class.javaObjectType ->
|
||||
!isAnimationEnabled(context) as T
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
||||
if (key == KEY && value is Boolean) {
|
||||
setAnimationEnabled(context, !value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// This KEY must match the key used in accessibility_color_and_motion.xml for this
|
||||
// preference, at least until the entire screen is migrated to Catalyst and that XML
|
||||
// is deleted. Use any key from the set of 3 toggle animation keys.
|
||||
const val KEY = Settings.Global.ANIMATOR_DURATION_SCALE
|
||||
|
||||
const val ANIMATION_ON_VALUE: Float = 1.0f
|
||||
const val ANIMATION_OFF_VALUE: Float = 0.0f
|
||||
|
||||
fun isAnimationEnabled(context: Context): Boolean {
|
||||
val storage = SettingsGlobalStore.get(context)
|
||||
// This pref treats animation as enabled if *any* of the animation types are enabled.
|
||||
for (animationSetting in getAnimationKeys()) {
|
||||
val animationValue: Float? = storage.getFloat(animationSetting)
|
||||
// Animation is enabled by default, so treat null as enabled.
|
||||
if (animationValue == null || animationValue > ANIMATION_OFF_VALUE) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun setAnimationEnabled(context: Context, enabled: Boolean) {
|
||||
val storage = SettingsGlobalStore.get(context)
|
||||
val value = if (enabled) ANIMATION_ON_VALUE else ANIMATION_OFF_VALUE
|
||||
for (animationSetting in getAnimationKeys()) {
|
||||
storage.setFloat(animationSetting, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAnimationKeys() =
|
||||
listOf(
|
||||
Settings.Global.WINDOW_ANIMATION_SCALE,
|
||||
Settings.Global.TRANSITION_ANIMATION_SCALE,
|
||||
Settings.Global.ANIMATOR_DURATION_SCALE,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,6 @@ public class RestrictedPreferenceHelper {
|
||||
final AccessibilityServiceInfo info = installedServices.get(i);
|
||||
final ResolveInfo resolveInfo = info.getResolveInfo();
|
||||
final String packageName = resolveInfo.serviceInfo.packageName;
|
||||
|
||||
final ComponentName componentName = new ComponentName(packageName,
|
||||
resolveInfo.serviceInfo.name);
|
||||
final boolean serviceEnabled = enabledServices.contains(componentName);
|
||||
@@ -102,10 +101,6 @@ public class RestrictedPreferenceHelper {
|
||||
*/
|
||||
public List<AccessibilityActivityPreference> createAccessibilityActivityPreferenceList(
|
||||
List<AccessibilityShortcutInfo> installedShortcuts) {
|
||||
final Set<ComponentName> enabledServices =
|
||||
AccessibilityUtils.getEnabledServicesFromSettings(mContext);
|
||||
final List<String> permittedServices = mDpm.getPermittedAccessibilityServices(
|
||||
UserHandle.myUserId());
|
||||
|
||||
final int installedShortcutsSize = installedShortcuts.size();
|
||||
final List<AccessibilityActivityPreference> preferenceList = new ArrayList<>(
|
||||
@@ -116,17 +111,12 @@ public class RestrictedPreferenceHelper {
|
||||
final ActivityInfo activityInfo = info.getActivityInfo();
|
||||
final ComponentName componentName = info.getComponentName();
|
||||
|
||||
final boolean serviceEnabled = enabledServices.contains(componentName);
|
||||
AccessibilityActivityPreference preference = new AccessibilityActivityPreference(
|
||||
mContext, componentName.getPackageName(), activityInfo.applicationInfo.uid,
|
||||
info);
|
||||
if (Flags.neverRestrictAccessibilityActivity()) {
|
||||
// Accessibility Activities do not have elevated privileges so restricting
|
||||
// them based on ECM or device admin does not give any value.
|
||||
preference.setEnabled(true);
|
||||
} else {
|
||||
setRestrictedPreferenceEnabled(preference, permittedServices, serviceEnabled);
|
||||
}
|
||||
// Accessibility Activities do not have elevated privileges so restricting
|
||||
// them based on ECM or device admin does not give any value.
|
||||
preference.setEnabled(true);
|
||||
preferenceList.add(preference);
|
||||
}
|
||||
return preferenceList;
|
||||
|
||||
@@ -17,17 +17,26 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
|
||||
import com.android.settings.bluetooth.Utils;
|
||||
import com.android.settings.connecteddevice.DevicePreferenceCallback;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
import com.android.settingslib.search.SearchIndexableRaw;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Controller to update the {@link androidx.preference.PreferenceCategory} for all
|
||||
@@ -39,11 +48,23 @@ public class SavedHearingDevicePreferenceController extends
|
||||
BaseBluetoothDevicePreferenceController implements LifecycleObserver, OnStart, OnResume,
|
||||
OnStop {
|
||||
|
||||
private static final String TAG = "SavedHearingDevicePreferenceController";
|
||||
private static final String SEARCH_DATA_KEY_PREFIX = "a11y_saved_hearing_device";
|
||||
private BluetoothDeviceUpdater mSavedHearingDeviceUpdater;
|
||||
private final LocalBluetoothManager mLocalBluetoothManager;
|
||||
|
||||
public SavedHearingDevicePreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mLocalBluetoothManager = Utils.getLocalBluetoothManager(context);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void init(SavedHearingDeviceUpdater savedHearingDeviceUpdater) {
|
||||
if (mSavedHearingDeviceUpdater != null) {
|
||||
throw new IllegalStateException("Should not call init() more than 1 time.");
|
||||
}
|
||||
mSavedHearingDeviceUpdater = savedHearingDeviceUpdater;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,4 +107,34 @@ public class SavedHearingDevicePreferenceController extends
|
||||
mSavedHearingDeviceUpdater.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
|
||||
if (Flags.fixA11ySettingsSearch()) {
|
||||
if (mLocalBluetoothManager == null) {
|
||||
Log.d(TAG, "Bluetooth is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
for (CachedBluetoothDevice cachedDevice :
|
||||
mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()) {
|
||||
|
||||
if (!SavedHearingDeviceUpdater.isSavedHearingAidDevice(cachedDevice)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
|
||||
// Include the identity address and add prefix to ensure the key is unique and
|
||||
// distinguish from Bluetooth's connected devices.
|
||||
data.key = SEARCH_DATA_KEY_PREFIX
|
||||
+ cachedDevice.getName() + cachedDevice.getIdentityAddress();
|
||||
data.title = cachedDevice.getName();
|
||||
data.summaryOn = mContext.getString(R.string.accessibility_hearingaid_title);
|
||||
data.screenTitle = mContext.getString(R.string.accessibility_hearingaid_title);
|
||||
rawData.add(data);
|
||||
}
|
||||
} else {
|
||||
super.updateDynamicRawDataToIndex(rawData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,14 +36,16 @@ public class SavedHearingDeviceUpdater extends SavedBluetoothDeviceUpdater {
|
||||
super(context, devicePreferenceCallback, /* showConnectedDevice= */ false, metricsCategory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
|
||||
static boolean isSavedHearingAidDevice(CachedBluetoothDevice cachedDevice) {
|
||||
final BluetoothDevice device = cachedDevice.getDevice();
|
||||
final boolean isSavedHearingAidDevice = cachedDevice.isHearingAidDevice()
|
||||
return cachedDevice.isHearingAidDevice()
|
||||
&& device.getBondState() == BluetoothDevice.BOND_BONDED
|
||||
&& !device.isConnected();
|
||||
}
|
||||
|
||||
return isSavedHearingAidDevice && isDeviceInCachedDevicesList(cachedDevice);
|
||||
@Override
|
||||
public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
|
||||
return isSavedHearingAidDevice(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,6 +30,8 @@ import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -64,7 +66,6 @@ public class TextReadingPreferenceFragment extends DashboardFragment {
|
||||
static final String RESET_KEY = "reset";
|
||||
static final String PREVIEW_KEY = "preview";
|
||||
private static final String NEED_RESET_SETTINGS = "need_reset_settings";
|
||||
private static final String LAST_PREVIEW_INDEX = "last_preview_index";
|
||||
private static final int UNKNOWN_INDEX = -1;
|
||||
|
||||
private FontWeightAdjustmentPreferenceController mFontWeightAdjustmentController;
|
||||
@@ -109,13 +110,6 @@ public class TextReadingPreferenceFragment extends DashboardFragment {
|
||||
if (savedInstanceState.getBoolean(NEED_RESET_SETTINGS)) {
|
||||
mResetStateListeners.forEach(ResetStateListener::resetState);
|
||||
}
|
||||
|
||||
if (savedInstanceState.containsKey(LAST_PREVIEW_INDEX)) {
|
||||
final int lastPreviewIndex = savedInstanceState.getInt(LAST_PREVIEW_INDEX);
|
||||
if (lastPreviewIndex != UNKNOWN_INDEX) {
|
||||
mPreviewController.setCurrentItem(lastPreviewIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,8 +244,6 @@ public class TextReadingPreferenceFragment extends DashboardFragment {
|
||||
if (mNeedResetSettings) {
|
||||
outState.putBoolean(NEED_RESET_SETTINGS, true);
|
||||
}
|
||||
|
||||
outState.putInt(LAST_PREVIEW_INDEX, mPreviewController.getCurrentItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -313,4 +305,9 @@ public class TextReadingPreferenceFragment extends DashboardFragment {
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_text_reading_options);
|
||||
|
||||
@Override
|
||||
public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
|
||||
return TextReadingScreen.KEY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -36,6 +38,7 @@ import com.android.settings.widget.DotsPageIndicator;
|
||||
* A {@link Preference} that could show the preview related to the text and reading options.
|
||||
*/
|
||||
public class TextReadingPreviewPreference extends Preference {
|
||||
private static final String KEY_LAST_INDEX = "last_preview_index";
|
||||
private int mCurrentItem;
|
||||
private int mLastLayerIndex;
|
||||
private PreviewPagerAdapter mPreviewAdapter;
|
||||
@@ -98,6 +101,22 @@ public class TextReadingPreviewPreference extends Preference {
|
||||
updatePagerAndIndicator(viewPager, pageIndicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Bundle state = new Bundle();
|
||||
state.putParcelable(null, super.onSaveInstanceState());
|
||||
state.putInt(KEY_LAST_INDEX, getCurrentItem());
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
super.onRestoreInstanceState(bundle.getParcelable(null));
|
||||
setCurrentItem(bundle.getInt(KEY_LAST_INDEX));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the minimum preview layout horizontal inner padding.
|
||||
*/
|
||||
|
||||
44
src/com/android/settings/accessibility/TextReadingScreen.kt
Normal file
44
src/com/android/settings/accessibility/TextReadingScreen.kt
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 com.android.settings.R
|
||||
import com.android.settings.flags.Flags
|
||||
import com.android.settingslib.metadata.ProvidePreferenceScreen
|
||||
import com.android.settingslib.metadata.preferenceHierarchy
|
||||
import com.android.settingslib.preference.PreferenceScreenCreator
|
||||
|
||||
@ProvidePreferenceScreen
|
||||
class TextReadingScreen : PreferenceScreenCreator {
|
||||
override val key: String
|
||||
get() = KEY
|
||||
|
||||
override val title: Int
|
||||
get() = R.string.accessibility_text_reading_options_title
|
||||
|
||||
override fun isFlagEnabled(context: Context) = Flags.catalystTextReadingScreen()
|
||||
|
||||
override fun fragmentClass() = TextReadingPreferenceFragment::class.java
|
||||
|
||||
override fun hasCompleteHierarchy() = false
|
||||
|
||||
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
|
||||
|
||||
companion object {
|
||||
const val KEY = "text_reading_screen"
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import static com.android.settings.accessibility.AccessibilityDialogUtils.Dialog
|
||||
import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
@@ -53,6 +54,7 @@ import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/** Fragment for providing toggle bar and basic accessibility service setup. */
|
||||
@@ -323,6 +325,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public void onToggleClicked(ShortcutPreference preference) {
|
||||
final int shortcutTypes = getUserPreferredShortcutTypes();
|
||||
@@ -337,8 +340,10 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
onAllowButtonFromShortcutToggleClicked();
|
||||
}
|
||||
} else {
|
||||
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes,
|
||||
mComponentName);
|
||||
getPrefContext().getSystemService(AccessibilityManager.class)
|
||||
.enableShortcutsForTargets(false, shortcutTypes,
|
||||
Set.of(mComponentName.flattenToString()),
|
||||
getPrefContext().getUserId());
|
||||
}
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
}
|
||||
@@ -385,8 +390,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
}
|
||||
|
||||
// Get Accessibility service name.
|
||||
mPackageName = getAccessibilityServiceInfo().getResolveInfo().loadLabel(
|
||||
getPackageManager());
|
||||
AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
mFeatureName = info == null ? "" : info.getResolveInfo().loadLabel(getPackageManager());
|
||||
|
||||
if (arguments.containsKey(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME)) {
|
||||
final String tileServiceComponentName = arguments.getString(
|
||||
@@ -452,15 +457,11 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
|
||||
@Override
|
||||
protected int getDefaultShortcutTypes() {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
boolean isAccessibilityTool = info != null && info.isAccessibilityTool();
|
||||
return !isAccessibilityTool || getTileComponentName() == null
|
||||
? super.getDefaultShortcutTypes()
|
||||
: ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
}
|
||||
|
||||
return super.getDefaultShortcutTypes();
|
||||
AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
boolean isAccessibilityTool = info != null && info.isAccessibilityTool();
|
||||
return !isAccessibilityTool || getTileComponentName() == null
|
||||
? super.getDefaultShortcutTypes()
|
||||
: ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
}
|
||||
|
||||
private void onAllowButtonFromEnableToggleClicked() {
|
||||
@@ -479,11 +480,14 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
mWarningDialog.dismiss();
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
void onAllowButtonFromShortcutToggleClicked() {
|
||||
mShortcutPreference.setChecked(true);
|
||||
|
||||
final int shortcutTypes = getUserPreferredShortcutTypes();
|
||||
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName);
|
||||
getPrefContext().getSystemService(AccessibilityManager.class)
|
||||
.enableShortcutsForTargets(true, shortcutTypes,
|
||||
Set.of(mComponentName.flattenToString()), getPrefContext().getUserId());
|
||||
|
||||
mIsDialogShown.set(false);
|
||||
showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
|
||||
|
||||
@@ -33,6 +33,8 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
@@ -52,7 +54,10 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
private static final String TAG = "ToggleColorInversionPreferenceFragment";
|
||||
private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED;
|
||||
|
||||
private static final String KEY_SHORTCUT_PREFERENCE = "color_inversion_shortcut_key";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SHORTCUT_PREFERENCE = "color_inversion_shortcut_key";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SWITCH_PREFERENCE = "color_inversion_switch_preference_key";
|
||||
|
||||
@Override
|
||||
protected void registerKeysToObserverCallback(
|
||||
@@ -69,13 +74,13 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
mComponentName = COLOR_INVERSION_COMPONENT_NAME;
|
||||
mPackageName = getText(R.string.accessibility_display_inversion_preference_title);
|
||||
mFeatureName = getText(R.string.accessibility_display_inversion_preference_title);
|
||||
mHtmlDescription = getText(R.string.accessibility_display_inversion_preference_subtitle);
|
||||
mTopIntroTitle = getText(R.string.accessibility_display_inversion_preference_intro_text);
|
||||
mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
||||
.authority(getPrefContext().getPackageName())
|
||||
.appendPath(String.valueOf(R.raw.a11y_color_inversion_banner))
|
||||
.build();
|
||||
.authority(getPrefContext().getPackageName())
|
||||
.appendPath(String.valueOf(R.raw.a11y_color_inversion_banner))
|
||||
.build();
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
updateFooterPreference();
|
||||
return view;
|
||||
@@ -131,6 +136,11 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
switchPreference.setTitle(R.string.accessibility_display_inversion_switch_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUseServicePreferenceKey() {
|
||||
return KEY_SWITCH_PREFERENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getText(R.string.accessibility_display_inversion_shortcut_title);
|
||||
@@ -165,7 +175,7 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
@Override
|
||||
int getUserShortcutTypes() {
|
||||
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
|
||||
mComponentName);
|
||||
mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,8 +186,8 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
@Override
|
||||
CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
|
||||
return getText(type == QuickSettingsTooltipType.GUIDE_TO_EDIT
|
||||
? R.string.accessibility_color_inversion_qs_tooltip_content
|
||||
: R.string.accessibility_color_inversion_auto_added_qs_tooltip_content);
|
||||
? R.string.accessibility_color_inversion_qs_tooltip_content
|
||||
: R.string.accessibility_color_inversion_auto_added_qs_tooltip_content);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -194,12 +204,22 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final List<SearchIndexableRaw> rawData = new ArrayList<>();
|
||||
final List<SearchIndexableRaw> rawData =
|
||||
super.getRawDataToIndex(context, enabled);
|
||||
|
||||
SearchIndexableRaw raw = new SearchIndexableRaw(context);
|
||||
raw.key = KEY_SHORTCUT_PREFERENCE;
|
||||
raw.title = context.getString(
|
||||
R.string.accessibility_display_inversion_shortcut_title);
|
||||
R.string.accessibility_display_inversion_shortcut_title);
|
||||
rawData.add(raw);
|
||||
|
||||
if (Flags.fixA11ySettingsSearch()) {
|
||||
SearchIndexableRaw mainPreferenceRaw = new SearchIndexableRaw(context);
|
||||
mainPreferenceRaw.key = KEY_SWITCH_PREFERENCE;
|
||||
mainPreferenceRaw.title = context.getString(
|
||||
R.string.accessibility_display_inversion_switch_title);
|
||||
rawData.add(mainPreferenceRaw);
|
||||
}
|
||||
return rawData;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ import static com.android.settings.accessibility.DaltonizerPreferenceUtil.isSecu
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -38,6 +39,7 @@ import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltip
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.search.SearchIndexableRaw;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -53,6 +55,11 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF
|
||||
private static final String KEY_PROTANOMALY = "daltonizer_mode_protanomaly";
|
||||
private static final String KEY_TRITANOMEALY = "daltonizer_mode_tritanomaly";
|
||||
private static final String KEY_GRAYSCALE = "daltonizer_mode_grayscale";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String KEY_SHORTCUT_PREFERENCE = "daltonizer_shortcut_key";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SWITCH_PREFERENCE = "daltonizer_switch_preference_key";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SATURATION = "daltonizer_saturation";
|
||||
|
||||
@@ -71,7 +78,7 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
mComponentName = DALTONIZER_COMPONENT_NAME;
|
||||
mPackageName = getText(com.android.settingslib.R
|
||||
mFeatureName = getText(com.android.settingslib.R
|
||||
.string.accessibility_display_daltonizer_preference_title);
|
||||
mHtmlDescription = getText(com.android.settingslib.R
|
||||
.string.accessibility_display_daltonizer_preference_subtitle);
|
||||
@@ -106,7 +113,7 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF
|
||||
final List<String> lists = new ArrayList<>();
|
||||
lists.add(KEY_TOP_INTRO_PREFERENCE);
|
||||
lists.add(KEY_PREVIEW);
|
||||
lists.add(KEY_USE_SERVICE_PREFERENCE);
|
||||
lists.add(getUseServicePreferenceKey());
|
||||
// Putting saturation level close to the preview so users can see what is changing.
|
||||
lists.add(KEY_SATURATION);
|
||||
lists.add(KEY_DEUTERANOMALY);
|
||||
@@ -170,6 +177,11 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF
|
||||
switchPreference.setTitle(R.string.accessibility_daltonizer_primary_switch_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUseServicePreferenceKey() {
|
||||
return KEY_SWITCH_PREFERENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getText(R.string.accessibility_daltonizer_shortcut_title);
|
||||
@@ -203,5 +215,27 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_daltonizer_settings);
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_daltonizer_settings) {
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final List<SearchIndexableRaw> rawData =
|
||||
super.getRawDataToIndex(context, enabled);
|
||||
|
||||
if (Flags.fixA11ySettingsSearch()) {
|
||||
SearchIndexableRaw shortcutRaw = new SearchIndexableRaw(context);
|
||||
shortcutRaw.key = KEY_SHORTCUT_PREFERENCE;
|
||||
shortcutRaw.title = context.getString(
|
||||
R.string.accessibility_daltonizer_shortcut_title);
|
||||
rawData.add(shortcutRaw);
|
||||
|
||||
SearchIndexableRaw mainSwitchRaw = new SearchIndexableRaw(context);
|
||||
mainSwitchRaw.key = KEY_SWITCH_PREFERENCE;
|
||||
mainSwitchRaw.title = context.getString(
|
||||
R.string.accessibility_daltonizer_primary_switch_title);
|
||||
rawData.add(mainSwitchRaw);
|
||||
}
|
||||
return rawData;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
|
||||
import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.getShortcutSummaryList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
@@ -34,7 +33,6 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.icu.text.CaseMap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -59,14 +57,12 @@ import androidx.preference.PreferenceScreen;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.widget.IllustrationPreference;
|
||||
@@ -76,7 +72,7 @@ import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for accessibility fragments with toggle, shortcut, some helper functions
|
||||
@@ -88,7 +84,6 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
public static final String KEY_GENERAL_CATEGORY = "general_categories";
|
||||
public static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
|
||||
protected static final String KEY_TOP_INTRO_PREFERENCE = "top_intro";
|
||||
protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service";
|
||||
protected static final String KEY_HTML_DESCRIPTION_PREFERENCE = "html_description";
|
||||
protected static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
|
||||
protected static final String KEY_SAVED_QS_TOOLTIP_TYPE = "qs_tooltip_type";
|
||||
@@ -110,7 +105,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
protected Intent mSettingsIntent;
|
||||
// The mComponentName maybe null, such as Magnify
|
||||
protected ComponentName mComponentName;
|
||||
protected CharSequence mPackageName;
|
||||
protected CharSequence mFeatureName;
|
||||
protected Uri mImageUri;
|
||||
protected CharSequence mHtmlDescription;
|
||||
protected CharSequence mTopIntroTitle;
|
||||
@@ -173,9 +168,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
final List<String> shortcutFeatureKeys = new ArrayList<>();
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
}
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_QS_TARGETS);
|
||||
return shortcutFeatureKeys;
|
||||
}
|
||||
|
||||
@@ -212,12 +205,12 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
mDialog = AccessibilityShortcutsTutorial
|
||||
.createAccessibilityTutorialDialogForSetupWizard(
|
||||
getPrefContext(), getUserPreferredShortcutTypes(),
|
||||
this::callOnTutorialDialogButtonClicked, mPackageName);
|
||||
this::callOnTutorialDialogButtonClicked, mFeatureName);
|
||||
} else {
|
||||
mDialog = AccessibilityShortcutsTutorial
|
||||
.createAccessibilityTutorialDialog(
|
||||
getPrefContext(), getUserPreferredShortcutTypes(),
|
||||
this::callOnTutorialDialogButtonClicked, mPackageName);
|
||||
this::callOnTutorialDialogButtonClicked, mFeatureName);
|
||||
}
|
||||
mDialog.setCanceledOnTouchOutside(false);
|
||||
return mDialog;
|
||||
@@ -326,12 +319,16 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
|
||||
protected void updateToggleServiceTitle(SettingsMainSwitchPreference switchPreference) {
|
||||
final CharSequence title =
|
||||
getString(R.string.accessibility_service_primary_switch_title, mPackageName);
|
||||
getString(R.string.accessibility_service_primary_switch_title, mFeatureName);
|
||||
switchPreference.setTitle(title);
|
||||
}
|
||||
|
||||
protected String getUseServicePreferenceKey() {
|
||||
return "use_service";
|
||||
}
|
||||
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getString(R.string.accessibility_shortcut_title, mPackageName);
|
||||
return getString(R.string.accessibility_shortcut_title, mFeatureName);
|
||||
}
|
||||
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
@@ -416,7 +413,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
final List<String> lists = new ArrayList<>();
|
||||
lists.add(KEY_TOP_INTRO_PREFERENCE);
|
||||
lists.add(KEY_ANIMATED_IMAGE);
|
||||
lists.add(KEY_USE_SERVICE_PREFERENCE);
|
||||
lists.add(getUseServicePreferenceKey());
|
||||
lists.add(KEY_GENERAL_CATEGORY);
|
||||
lists.add(KEY_HTML_DESCRIPTION_PREFERENCE);
|
||||
return lists;
|
||||
@@ -481,7 +478,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
|
||||
private void initToggleServiceSwitchPreference() {
|
||||
mToggleServiceSwitchPreference = new SettingsMainSwitchPreference(getPrefContext());
|
||||
mToggleServiceSwitchPreference.setKey(KEY_USE_SERVICE_PREFERENCE);
|
||||
mToggleServiceSwitchPreference.setKey(getUseServicePreferenceKey());
|
||||
if (getArguments().containsKey(AccessibilitySettings.EXTRA_CHECKED)) {
|
||||
final boolean enabled = getArguments().getBoolean(AccessibilitySettings.EXTRA_CHECKED);
|
||||
mToggleServiceSwitchPreference.setChecked(enabled);
|
||||
@@ -577,7 +574,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
screen.addPreference(mHtmlFooterPreference);
|
||||
|
||||
// TODO(b/171272809): Migrate to DashboardFragment.
|
||||
final String title = getString(R.string.accessibility_introduction_title, mPackageName);
|
||||
final String title = getString(R.string.accessibility_introduction_title, mFeatureName);
|
||||
mFooterPreferenceController = new AccessibilityFooterPreferenceController(
|
||||
screen.getContext(), mHtmlFooterPreference.getKey());
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
@@ -602,7 +599,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
private void initFooterPreference() {
|
||||
if (!TextUtils.isEmpty(mDescription)) {
|
||||
createFooterPreference(getPreferenceScreen(), mDescription,
|
||||
getString(R.string.accessibility_introduction_title, mPackageName));
|
||||
getString(R.string.accessibility_introduction_title, mFeatureName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,10 +624,6 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
mFooterPreferenceController.displayPreference(screen);
|
||||
}
|
||||
|
||||
private boolean hasShortcutType(int value, @UserShortcutType int type) {
|
||||
return (value & type) == type;
|
||||
}
|
||||
|
||||
protected CharSequence getShortcutTypeSummary(Context context) {
|
||||
if (!mShortcutPreference.isSettingsEditable()) {
|
||||
return context.getText(R.string.accessibility_shortcut_edit_dialog_title_hardware);
|
||||
@@ -640,47 +633,9 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
return context.getText(R.string.accessibility_shortcut_state_off);
|
||||
}
|
||||
|
||||
// LINT.IfChange(shortcut_type_ui_order)
|
||||
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(
|
||||
context, mComponentName.flattenToString(), getDefaultShortcutTypes());
|
||||
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if (hasShortcutType(shortcutTypes, QUICK_SETTINGS)) {
|
||||
final CharSequence qsTitle = context.getText(
|
||||
R.string.accessibility_feature_shortcut_setting_summary_quick_settings);
|
||||
list.add(qsTitle);
|
||||
}
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, SOFTWARE)) {
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, HARDWARE)) {
|
||||
final CharSequence hardwareTitle = context.getText(
|
||||
R.string.accessibility_shortcut_hardware_keyword);
|
||||
list.add(hardwareTitle);
|
||||
}
|
||||
// LINT.ThenChange(/res/xml/accessibility_edit_shortcuts.xml:shortcut_type_ui_order)
|
||||
|
||||
// Show software shortcut if first time to use.
|
||||
if (list.isEmpty()) {
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
|
||||
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
|
||||
null, LocaleUtils.getConcatenatedString(list));
|
||||
}
|
||||
|
||||
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);
|
||||
return getShortcutSummaryList(context, shortcutTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -731,13 +686,12 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
}
|
||||
|
||||
final int shortcutTypes = getUserPreferredShortcutTypes();
|
||||
if (preference.isChecked()) {
|
||||
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
|
||||
mComponentName);
|
||||
final boolean isChecked = preference.isChecked();
|
||||
getPrefContext().getSystemService(AccessibilityManager.class).enableShortcutsForTargets(
|
||||
isChecked, shortcutTypes,
|
||||
Set.of(mComponentName.flattenToString()), getPrefContext().getUserId());
|
||||
if (isChecked) {
|
||||
showDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
|
||||
} else {
|
||||
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), shortcutTypes,
|
||||
mComponentName);
|
||||
}
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
}
|
||||
@@ -794,44 +748,13 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated made obsolete by quick settings rollout.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
private void showQuickSettingsTooltipIfNeeded() {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
// Don't show Quick Settings tooltip
|
||||
return;
|
||||
}
|
||||
final ComponentName tileComponentName = getTileComponentName();
|
||||
if (tileComponentName == null) {
|
||||
// Returns if no tile service assigned.
|
||||
return;
|
||||
}
|
||||
|
||||
Activity activity = getActivity();
|
||||
if (activity != null && WizardManagerHelper.isAnySetupWizard(activity.getIntent())) {
|
||||
// Don't show QuickSettingsTooltip in Setup Wizard
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
|
||||
getContext(), tileComponentName)) {
|
||||
// Returns if quick settings tooltip only show once.
|
||||
return;
|
||||
}
|
||||
|
||||
final CharSequence content = getTileTooltipContent(mNeedsQSTooltipType);
|
||||
if (TextUtils.isEmpty(content)) {
|
||||
// Returns if no content of tile tooltip assigned.
|
||||
return;
|
||||
}
|
||||
|
||||
final int imageResId = mNeedsQSTooltipType == QuickSettingsTooltipType.GUIDE_TO_EDIT
|
||||
? R.drawable.accessibility_qs_tooltip_illustration
|
||||
: R.drawable.accessibility_auto_added_qs_tooltip_illustration;
|
||||
mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(getContext());
|
||||
mTooltipWindow.setup(content, imageResId);
|
||||
mTooltipWindow.showAtTopCenter(getView());
|
||||
AccessibilityQuickSettingUtils.optInValueToSharedPreferences(getContext(),
|
||||
tileComponentName);
|
||||
mNeedsQSTooltipReshow = false;
|
||||
}
|
||||
|
||||
/** Returns user visible name of the tile by given {@link ComponentName}. */
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
@@ -41,6 +42,7 @@ import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.widget.SeekBarPreference;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.search.SearchIndexableRaw;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -52,6 +54,10 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
private static final String TAG = "ToggleReduceBrightColorsPreferenceFragment";
|
||||
private static final String KEY_INTENSITY = "rbc_intensity";
|
||||
private static final String KEY_PERSIST = "rbc_persist";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SHORTCUT = "rbc_shortcut";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SWITCH = "rbc_switch";
|
||||
private static final String REDUCE_BRIGHT_COLORS_ACTIVATED_KEY =
|
||||
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED;
|
||||
|
||||
@@ -78,7 +84,7 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
.appendPath(String.valueOf(R.raw.a11y_extra_dim_banner))
|
||||
.build();
|
||||
mComponentName = REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
|
||||
mPackageName = getText(R.string.reduce_bright_colors_preference_title);
|
||||
mFeatureName = getText(R.string.reduce_bright_colors_preference_title);
|
||||
mHtmlDescription = getText(R.string.reduce_bright_colors_preference_subtitle);
|
||||
mTopIntroTitle = getText(R.string.reduce_bright_colors_preference_intro_text);
|
||||
mRbcIntensityPreferenceController =
|
||||
@@ -197,11 +203,43 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUseServicePreferenceKey() {
|
||||
return KEY_SWITCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getShortcutPreferenceKey() {
|
||||
return KEY_SHORTCUT;
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.reduce_bright_colors_settings) {
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
return ColorDisplayManager.isReduceBrightColorsAvailable(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final List<SearchIndexableRaw> rawData =
|
||||
super.getRawDataToIndex(context, enabled);
|
||||
|
||||
if (Flags.fixA11ySettingsSearch()) {
|
||||
SearchIndexableRaw shortcutRaw = new SearchIndexableRaw(context);
|
||||
shortcutRaw.key = KEY_SHORTCUT;
|
||||
shortcutRaw.title = context.getString(
|
||||
R.string.reduce_bright_colors_shortcut_title);
|
||||
rawData.add(shortcutRaw);
|
||||
|
||||
SearchIndexableRaw mainSwitchRaw = new SearchIndexableRaw(context);
|
||||
mainSwitchRaw.key = KEY_SWITCH;
|
||||
mainSwitchRaw.title = context.getString(
|
||||
R.string.reduce_bright_colors_switch_title);
|
||||
rawData.add(mainSwitchRaw);
|
||||
}
|
||||
return rawData;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.settings.accessibility;
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
|
||||
@@ -27,6 +28,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh
|
||||
import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.getShortcutSummaryList;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
@@ -34,7 +36,6 @@ import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.icu.text.CaseMap;
|
||||
import android.icu.text.MessageFormat;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -53,36 +54,41 @@ import androidx.annotation.StringRes;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
|
||||
import com.android.internal.accessibility.util.ShortcutUtils;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.accessibility.Flags;
|
||||
import com.android.settings.DialogCreatable;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.search.Indexable;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.widget.IllustrationPreference;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Fragment that shows the actual UI for providing basic magnification accessibility service setup
|
||||
* and does not have toggle bar to turn on service to use.
|
||||
*/
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
ToggleFeaturePreferenceFragment implements
|
||||
MagnificationModePreferenceController.DialogHelper {
|
||||
|
||||
private static final String TAG = "ToggleScreenMagnificationPreferenceFragment";
|
||||
@VisibleForTesting
|
||||
static final String KEY_MAGNIFICATION_SHORTCUT_PREFERENCE = "magnification_shortcut_preference";
|
||||
private static final char COMPONENT_NAME_SEPARATOR = ':';
|
||||
private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
|
||||
new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
|
||||
@@ -106,7 +112,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
mPackageName = getString(R.string.accessibility_screen_magnification_title);
|
||||
mFeatureName = getString(R.string.accessibility_screen_magnification_title);
|
||||
mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
||||
.authority(getPrefContext().getPackageName())
|
||||
.appendPath(String.valueOf(R.raw.a11y_magnification_banner))
|
||||
@@ -181,38 +187,29 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isWindowMagnificationSupported(Context context) {
|
||||
return context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_magnification_area)
|
||||
&& context.getPackageManager().hasSystemFeature(
|
||||
PackageManager.FEATURE_WINDOW_MAGNIFICATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initSettingsPreference() {
|
||||
// If the device doesn't support window magnification feature, it should hide the
|
||||
// settings preference.
|
||||
final boolean supportWindowMagnification =
|
||||
getContext().getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_magnification_area)
|
||||
&& getContext().getPackageManager().hasSystemFeature(
|
||||
PackageManager.FEATURE_WINDOW_MAGNIFICATION);
|
||||
if (!supportWindowMagnification) {
|
||||
if (!isWindowMagnificationSupported(getContext())) {
|
||||
return;
|
||||
}
|
||||
mSettingsPreference = new Preference(getPrefContext());
|
||||
mSettingsPreference.setTitle(R.string.accessibility_magnification_mode_title);
|
||||
mSettingsPreference.setKey(MagnificationModePreferenceController.PREF_KEY);
|
||||
mSettingsPreference.setPersistent(false);
|
||||
|
||||
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
|
||||
generalCategory.addPreference(mSettingsPreference);
|
||||
|
||||
final MagnificationModePreferenceController magnificationModePreferenceController =
|
||||
new MagnificationModePreferenceController(getContext(),
|
||||
MagnificationModePreferenceController.PREF_KEY);
|
||||
magnificationModePreferenceController.setDialogHelper(this);
|
||||
getSettingsLifecycle().addObserver(magnificationModePreferenceController);
|
||||
magnificationModePreferenceController.displayPreference(getPreferenceScreen());
|
||||
addPreferenceController(magnificationModePreferenceController);
|
||||
|
||||
// LINT.IfChange(preference_list)
|
||||
addMagnificationModeSetting(generalCategory);
|
||||
addFollowTypingSetting(generalCategory);
|
||||
addOneFingerPanningSetting(generalCategory);
|
||||
addAlwaysOnSetting(generalCategory);
|
||||
addJoystickSetting(generalCategory);
|
||||
// LINT.ThenChange(search_data)
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,22 +230,44 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
&& !Flags.enableMagnificationOneFingerPanningGesture()) {
|
||||
String summary = MessageFormat.format(
|
||||
context.getString(R.string.accessibility_screen_magnification_summary),
|
||||
new Object[]{1, 2, 3, 4, 5});
|
||||
new Object[]{1, 2, 3, 4, 5});
|
||||
arguments.putCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, summary);
|
||||
}
|
||||
|
||||
super.onProcessArguments(arguments);
|
||||
}
|
||||
|
||||
private static Preference createMagnificationModePreference(Context context) {
|
||||
final Preference pref = new Preference(context);
|
||||
pref.setTitle(R.string.accessibility_magnification_mode_title);
|
||||
pref.setKey(MagnificationModePreferenceController.PREF_KEY);
|
||||
pref.setPersistent(false);
|
||||
return pref;
|
||||
}
|
||||
|
||||
private void addMagnificationModeSetting(PreferenceCategory generalCategory) {
|
||||
mSettingsPreference = createMagnificationModePreference(getPrefContext());
|
||||
generalCategory.addPreference(mSettingsPreference);
|
||||
|
||||
final MagnificationModePreferenceController magnificationModePreferenceController =
|
||||
new MagnificationModePreferenceController(getContext(),
|
||||
MagnificationModePreferenceController.PREF_KEY);
|
||||
magnificationModePreferenceController.setDialogHelper(this);
|
||||
getSettingsLifecycle().addObserver(magnificationModePreferenceController);
|
||||
magnificationModePreferenceController.displayPreference(getPreferenceScreen());
|
||||
addPreferenceController(magnificationModePreferenceController);
|
||||
}
|
||||
|
||||
private static Preference createFollowTypingPreference(Context context) {
|
||||
final Preference pref = new SwitchPreferenceCompat(context);
|
||||
pref.setTitle(R.string.accessibility_screen_magnification_follow_typing_title);
|
||||
pref.setSummary(R.string.accessibility_screen_magnification_follow_typing_summary);
|
||||
pref.setKey(MagnificationFollowTypingPreferenceController.PREF_KEY);
|
||||
return pref;
|
||||
}
|
||||
|
||||
private void addFollowTypingSetting(PreferenceCategory generalCategory) {
|
||||
var followingTypingSwitchPreference = new SwitchPreferenceCompat(getPrefContext());
|
||||
followingTypingSwitchPreference.setTitle(
|
||||
R.string.accessibility_screen_magnification_follow_typing_title);
|
||||
followingTypingSwitchPreference.setSummary(
|
||||
R.string.accessibility_screen_magnification_follow_typing_summary);
|
||||
followingTypingSwitchPreference.setKey(
|
||||
MagnificationFollowTypingPreferenceController.PREF_KEY);
|
||||
generalCategory.addPreference(followingTypingSwitchPreference);
|
||||
generalCategory.addPreference(createFollowTypingPreference(getPrefContext()));
|
||||
|
||||
var followTypingPreferenceController = new MagnificationFollowTypingPreferenceController(
|
||||
getContext(), MagnificationFollowTypingPreferenceController.PREF_KEY);
|
||||
@@ -257,8 +276,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
addPreferenceController(followTypingPreferenceController);
|
||||
}
|
||||
|
||||
private boolean isAlwaysOnSettingEnabled() {
|
||||
final boolean defaultValue = getContext().getResources().getBoolean(
|
||||
private static boolean isAlwaysOnSupported(Context context) {
|
||||
final boolean defaultValue = context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_magnification_always_on_enabled);
|
||||
|
||||
return DeviceConfig.getBoolean(
|
||||
@@ -268,19 +287,21 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
);
|
||||
}
|
||||
|
||||
private static Preference createAlwaysOnPreference(Context context) {
|
||||
final Preference pref = new SwitchPreferenceCompat(context);
|
||||
pref.setTitle(R.string.accessibility_screen_magnification_always_on_title);
|
||||
pref.setSummary(R.string.accessibility_screen_magnification_always_on_summary);
|
||||
pref.setKey(MagnificationAlwaysOnPreferenceController.PREF_KEY);
|
||||
return pref;
|
||||
}
|
||||
|
||||
private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
|
||||
if (!isAlwaysOnSettingEnabled()) {
|
||||
if (!isAlwaysOnSupported(getContext())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var alwaysOnPreference = new SwitchPreferenceCompat(getPrefContext());
|
||||
alwaysOnPreference.setTitle(
|
||||
R.string.accessibility_screen_magnification_always_on_title);
|
||||
alwaysOnPreference.setSummary(
|
||||
R.string.accessibility_screen_magnification_always_on_summary);
|
||||
alwaysOnPreference.setKey(
|
||||
MagnificationAlwaysOnPreferenceController.PREF_KEY);
|
||||
generalCategory.addPreference(alwaysOnPreference);
|
||||
final Preference pref = createAlwaysOnPreference(getPrefContext());
|
||||
generalCategory.addPreference(pref);
|
||||
|
||||
var alwaysOnPreferenceController = new MagnificationAlwaysOnPreferenceController(
|
||||
getContext(), MagnificationAlwaysOnPreferenceController.PREF_KEY);
|
||||
@@ -290,17 +311,24 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
addPreferenceController(alwaysOnPreferenceController);
|
||||
}
|
||||
|
||||
private static Preference createOneFingerPanningPreference(Context context) {
|
||||
final Preference pref = new SwitchPreferenceCompat(context);
|
||||
pref.setTitle(R.string.accessibility_magnification_one_finger_panning_title);
|
||||
pref.setKey(MagnificationOneFingerPanningPreferenceController.PREF_KEY);
|
||||
return pref;
|
||||
}
|
||||
|
||||
private static boolean isOneFingerPanningSupported() {
|
||||
return Flags.enableMagnificationOneFingerPanningGesture();
|
||||
}
|
||||
|
||||
private void addOneFingerPanningSetting(PreferenceCategory generalCategory) {
|
||||
if (!Flags.enableMagnificationOneFingerPanningGesture()) {
|
||||
if (!isOneFingerPanningSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oneFingerPanningPreference = new SwitchPreferenceCompat(getPrefContext());
|
||||
oneFingerPanningPreference.setTitle(
|
||||
R.string.accessibility_magnification_one_finger_panning_title);
|
||||
oneFingerPanningPreference.setKey(
|
||||
MagnificationOneFingerPanningPreferenceController.PREF_KEY);
|
||||
generalCategory.addPreference(oneFingerPanningPreference);
|
||||
final Preference pref = createOneFingerPanningPreference(getPrefContext());
|
||||
generalCategory.addPreference(pref);
|
||||
|
||||
mOneFingerPanningPreferenceController =
|
||||
new MagnificationOneFingerPanningPreferenceController(getContext());
|
||||
@@ -310,23 +338,28 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
addPreferenceController(mOneFingerPanningPreferenceController);
|
||||
}
|
||||
|
||||
private void addJoystickSetting(PreferenceCategory generalCategory) {
|
||||
if (!DeviceConfig.getBoolean(
|
||||
private static Preference createJoystickPreference(Context context) {
|
||||
final Preference pref = new SwitchPreferenceCompat(context);
|
||||
pref.setTitle(R.string.accessibility_screen_magnification_joystick_title);
|
||||
pref.setSummary(R.string.accessibility_screen_magnification_joystick_summary);
|
||||
pref.setKey(MagnificationJoystickPreferenceController.PREF_KEY);
|
||||
return pref;
|
||||
}
|
||||
|
||||
private static boolean isJoystickSupported() {
|
||||
return DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
|
||||
"MagnificationJoystick__enable_magnification_joystick",
|
||||
false
|
||||
)) {
|
||||
false);
|
||||
}
|
||||
|
||||
private void addJoystickSetting(PreferenceCategory generalCategory) {
|
||||
if (!isJoystickSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TwoStatePreference joystickPreference = new SwitchPreferenceCompat(getPrefContext());
|
||||
joystickPreference.setTitle(
|
||||
R.string.accessibility_screen_magnification_joystick_title);
|
||||
joystickPreference.setSummary(
|
||||
R.string.accessibility_screen_magnification_joystick_summary);
|
||||
joystickPreference.setKey(
|
||||
MagnificationJoystickPreferenceController.PREF_KEY);
|
||||
generalCategory.addPreference(joystickPreference);
|
||||
final Preference pref = createJoystickPreference(getPrefContext());
|
||||
generalCategory.addPreference(pref);
|
||||
|
||||
MagnificationJoystickPreferenceController joystickPreferenceController =
|
||||
new MagnificationJoystickPreferenceController(
|
||||
@@ -348,31 +381,15 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
mDialogDelegate = delegate;
|
||||
}
|
||||
|
||||
private boolean hasShortcutType(int value, @UserShortcutType int type) {
|
||||
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 void registerKeysToObserverCallback(
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
super.registerKeysToObserverCallback(contentObserver);
|
||||
|
||||
var keysToObserve = List.of(
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED,
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED,
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED
|
||||
);
|
||||
contentObserver.registerKeysToObserverCallback(keysToObserve,
|
||||
key -> updatePreferencesState());
|
||||
@@ -423,47 +440,9 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
return context.getText(R.string.switch_off_text);
|
||||
}
|
||||
|
||||
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
|
||||
MAGNIFICATION_CONTROLLER_NAME);
|
||||
|
||||
// LINT.IfChange(shortcut_type_ui_order)
|
||||
final List<CharSequence> list = new ArrayList<>();
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if (hasShortcutType(shortcutTypes, QUICK_SETTINGS)) {
|
||||
final CharSequence qsTitle = context.getText(
|
||||
R.string.accessibility_feature_shortcut_setting_summary_quick_settings);
|
||||
list.add(qsTitle);
|
||||
}
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, SOFTWARE)) {
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, HARDWARE)) {
|
||||
final CharSequence hardwareTitle = context.getText(
|
||||
R.string.accessibility_shortcut_hardware_keyword);
|
||||
list.add(hardwareTitle);
|
||||
}
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (hasShortcutType(shortcutTypes, TWOFINGER_DOUBLETAP)) {
|
||||
final CharSequence twoFingerDoubleTapTitle = context.getString(
|
||||
R.string.accessibility_shortcut_two_finger_double_tap_keyword, 2);
|
||||
list.add(twoFingerDoubleTapTitle);
|
||||
}
|
||||
}
|
||||
if (hasShortcutType(shortcutTypes, TRIPLETAP)) {
|
||||
final CharSequence tripleTapTitle = context.getText(
|
||||
R.string.accessibility_shortcut_triple_tap_keyword);
|
||||
list.add(tripleTapTitle);
|
||||
}
|
||||
// LINT.ThenChange(/res/xml/accessibility_edit_shortcuts.xml:shortcut_type_ui_order)
|
||||
|
||||
// Show software shortcut if first time to use.
|
||||
if (list.isEmpty()) {
|
||||
list.add(getSoftwareShortcutTypeSummary(context));
|
||||
}
|
||||
|
||||
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
|
||||
null, LocaleUtils.getConcatenatedString(list));
|
||||
return getShortcutSummaryList(context,
|
||||
PreferredShortcuts.retrieveUserShortcutType(context,
|
||||
MAGNIFICATION_CONTROLLER_NAME));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -571,6 +550,11 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
generalCategory.addPreference(mShortcutPreference);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getShortcutPreferenceKey() {
|
||||
return KEY_MAGNIFICATION_SHORTCUT_PREFERENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getText(R.string.accessibility_screen_magnification_shortcut_title);
|
||||
@@ -595,76 +579,38 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
if (((shortcutTypes & TRIPLETAP) == TRIPLETAP)) {
|
||||
optInMagnificationValueToSettings(context, TRIPLETAP);
|
||||
}
|
||||
if (((shortcutTypes & GESTURE) == GESTURE)) {
|
||||
optInMagnificationValueToSettings(context, GESTURE);
|
||||
}
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (((shortcutTypes & TWOFINGER_DOUBLETAP)
|
||||
== TWOFINGER_DOUBLETAP)) {
|
||||
optInMagnificationValueToSettings(context, TWOFINGER_DOUBLETAP);
|
||||
}
|
||||
}
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if (((shortcutTypes & QUICK_SETTINGS)
|
||||
== QUICK_SETTINGS)) {
|
||||
optInMagnificationValueToSettings(context, QUICK_SETTINGS);
|
||||
}
|
||||
if (((shortcutTypes & QUICK_SETTINGS)
|
||||
== QUICK_SETTINGS)) {
|
||||
optInMagnificationValueToSettings(context, QUICK_SETTINGS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use
|
||||
* {@link AccessibilityManager#enableShortcutsForTargets(boolean, int, Set, int)} instead.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
private static void optInMagnificationValueToSettings(
|
||||
Context context, @UserShortcutType int shortcutType) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ true,
|
||||
shortcutType,
|
||||
Set.of(MAGNIFICATION_CONTROLLER_NAME),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (shortcutType == TRIPLETAP) {
|
||||
Settings.Secure.putInt(context.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (shortcutType == TWOFINGER_DOUBLETAP) {
|
||||
Settings.Secure.putInt(
|
||||
context.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
|
||||
ON);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMagnificationValueInSettings(context, shortcutType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType);
|
||||
final String targetString = Settings.Secure.getString(context.getContentResolver(),
|
||||
targetKey);
|
||||
final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
|
||||
|
||||
if (!TextUtils.isEmpty(targetString)) {
|
||||
joiner.add(targetString);
|
||||
}
|
||||
joiner.add(MAGNIFICATION_CONTROLLER_NAME);
|
||||
|
||||
Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
|
||||
// The size setting defaults to unknown. If the user has ever manually changed the size
|
||||
// before, we do not automatically change it.
|
||||
if (shortcutType == SOFTWARE
|
||||
&& Settings.Secure.getInt(context.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
|
||||
FloatingMenuSizePreferenceController.Size.UNKNOWN)
|
||||
== FloatingMenuSizePreferenceController.Size.UNKNOWN) {
|
||||
Settings.Secure.putInt(context.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
|
||||
FloatingMenuSizePreferenceController.Size.LARGE);
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ true,
|
||||
shortcutType,
|
||||
Set.of(MAGNIFICATION_CONTROLLER_NAME),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,94 +626,58 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
if (((shortcutTypes & TRIPLETAP) == TRIPLETAP)) {
|
||||
optOutMagnificationValueFromSettings(context, TRIPLETAP);
|
||||
}
|
||||
if (((shortcutTypes & GESTURE) == GESTURE)) {
|
||||
optOutMagnificationValueFromSettings(context, GESTURE);
|
||||
}
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (((shortcutTypes & TWOFINGER_DOUBLETAP)
|
||||
== TWOFINGER_DOUBLETAP)) {
|
||||
optOutMagnificationValueFromSettings(context, TWOFINGER_DOUBLETAP);
|
||||
}
|
||||
}
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
if (((shortcutTypes & QUICK_SETTINGS)
|
||||
if (((shortcutTypes & QUICK_SETTINGS)
|
||||
== QUICK_SETTINGS)) {
|
||||
optOutMagnificationValueFromSettings(context, QUICK_SETTINGS);
|
||||
}
|
||||
optOutMagnificationValueFromSettings(context, QUICK_SETTINGS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use
|
||||
* {@link AccessibilityManager#enableShortcutsForTargets(boolean, int, Set, int)} instead.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
private static void optOutMagnificationValueFromSettings(Context context,
|
||||
@UserShortcutType int shortcutType) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ false,
|
||||
shortcutType,
|
||||
Set.of(MAGNIFICATION_CONTROLLER_NAME),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
return;
|
||||
AccessibilityManager a11yManager = context.getSystemService(AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(
|
||||
/* enable= */ false,
|
||||
shortcutType,
|
||||
Set.of(MAGNIFICATION_CONTROLLER_NAME),
|
||||
UserHandle.myUserId()
|
||||
);
|
||||
}
|
||||
|
||||
if (shortcutType == TRIPLETAP) {
|
||||
Settings.Secure.putInt(context.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (shortcutType == TWOFINGER_DOUBLETAP) {
|
||||
Settings.Secure.putInt(
|
||||
context.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
|
||||
OFF);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final String targetKey = AccessibilityUtil.convertKeyFromSettings(shortcutType);
|
||||
final String targetString = Settings.Secure.getString(context.getContentResolver(),
|
||||
targetKey);
|
||||
|
||||
if (TextUtils.isEmpty(targetString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
|
||||
|
||||
sStringColonSplitter.setString(targetString);
|
||||
while (sStringColonSplitter.hasNext()) {
|
||||
final String name = sStringColonSplitter.next();
|
||||
if (TextUtils.isEmpty(name) || MAGNIFICATION_CONTROLLER_NAME.equals(name)) {
|
||||
continue;
|
||||
}
|
||||
joiner.add(name);
|
||||
}
|
||||
|
||||
Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean hasMagnificationValuesInSettings(Context context, int shortcutTypes) {
|
||||
boolean exist = false;
|
||||
|
||||
if ((shortcutTypes & SOFTWARE) == SOFTWARE) {
|
||||
exist = hasMagnificationValueInSettings(context, SOFTWARE);
|
||||
}
|
||||
if (((shortcutTypes & HARDWARE) == HARDWARE)) {
|
||||
exist |= hasMagnificationValueInSettings(context, HARDWARE);
|
||||
}
|
||||
if (((shortcutTypes & TRIPLETAP) == TRIPLETAP)) {
|
||||
exist |= hasMagnificationValueInSettings(context, TRIPLETAP);
|
||||
}
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (((shortcutTypes & TWOFINGER_DOUBLETAP)
|
||||
== TWOFINGER_DOUBLETAP)) {
|
||||
exist |= hasMagnificationValueInSettings(context,
|
||||
TWOFINGER_DOUBLETAP);
|
||||
for (int shortcutType : AccessibilityUtil.SHORTCUTS_ORDER_IN_UI) {
|
||||
if ((shortcutTypes & shortcutType) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (((shortcutType & TWOFINGER_DOUBLETAP)
|
||||
== TWOFINGER_DOUBLETAP)
|
||||
&& !Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
continue;
|
||||
}
|
||||
if (hasMagnificationValueInSettings(context, shortcutType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return exist;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasMagnificationValueInSettings(Context context,
|
||||
@@ -776,7 +686,6 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
return Settings.Secure.getInt(context.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
|
||||
}
|
||||
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (shortcutType == TWOFINGER_DOUBLETAP) {
|
||||
return Settings.Secure.getInt(context.getContentResolver(),
|
||||
@@ -803,22 +712,21 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use
|
||||
* {@link ShortcutUtils#getEnabledShortcutTypes(Context, String)} instead.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
private static int getUserShortcutTypeFromSettings(Context context) {
|
||||
int shortcutTypes = DEFAULT;
|
||||
if (hasMagnificationValuesInSettings(context, SOFTWARE)) {
|
||||
shortcutTypes |= SOFTWARE;
|
||||
}
|
||||
if (hasMagnificationValuesInSettings(context, HARDWARE)) {
|
||||
shortcutTypes |= HARDWARE;
|
||||
}
|
||||
if (hasMagnificationValuesInSettings(context, TRIPLETAP)) {
|
||||
shortcutTypes |= TRIPLETAP;
|
||||
}
|
||||
if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
|
||||
if (hasMagnificationValuesInSettings(context, TWOFINGER_DOUBLETAP)) {
|
||||
shortcutTypes |= TWOFINGER_DOUBLETAP;
|
||||
for (int shortcutType : AccessibilityUtil.SHORTCUTS_ORDER_IN_UI) {
|
||||
if (hasMagnificationValueInSettings(context, shortcutType)) {
|
||||
shortcutTypes |= shortcutType;
|
||||
}
|
||||
}
|
||||
|
||||
return shortcutTypes;
|
||||
}
|
||||
|
||||
@@ -832,8 +740,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
final int userShortcutType = getUserShortcutTypeFromSettings(context);
|
||||
final CharSequence featureState =
|
||||
(userShortcutType != DEFAULT)
|
||||
? context.getText(R.string.accessibility_summary_shortcut_enabled)
|
||||
: context.getText(R.string.generic_accessibility_feature_shortcut_off);
|
||||
? context.getText(R.string.accessibility_summary_shortcut_enabled)
|
||||
: context.getText(R.string.generic_accessibility_feature_shortcut_off);
|
||||
final CharSequence featureSummary = context.getText(R.string.magnification_feature_summary);
|
||||
return context.getString(
|
||||
com.android.settingslib.R.string.preference_summary_default_combination,
|
||||
@@ -845,4 +753,81 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
return PreferredShortcuts.retrieveUserShortcutType(
|
||||
getPrefContext(), MAGNIFICATION_CONTROLLER_NAME);
|
||||
}
|
||||
|
||||
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
// LINT.IfChange(search_data)
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final List<SearchIndexableRaw> rawData =
|
||||
super.getRawDataToIndex(context, enabled);
|
||||
|
||||
if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) {
|
||||
return rawData;
|
||||
}
|
||||
|
||||
rawData.add(createShortcutPreferenceSearchData(context));
|
||||
Stream.of(
|
||||
createMagnificationModePreference(context),
|
||||
createFollowTypingPreference(context),
|
||||
createOneFingerPanningPreference(context),
|
||||
createAlwaysOnPreference(context),
|
||||
createJoystickPreference(context)
|
||||
)
|
||||
.forEach(pref ->
|
||||
rawData.add(createPreferenceSearchData(context, pref)));
|
||||
return rawData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
final List<String> niks = super.getNonIndexableKeys(context);
|
||||
|
||||
if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) {
|
||||
return niks;
|
||||
}
|
||||
|
||||
if (!isWindowMagnificationSupported(context)) {
|
||||
niks.add(MagnificationModePreferenceController.PREF_KEY);
|
||||
niks.add(MagnificationFollowTypingPreferenceController.PREF_KEY);
|
||||
niks.add(MagnificationOneFingerPanningPreferenceController.PREF_KEY);
|
||||
niks.add(MagnificationAlwaysOnPreferenceController.PREF_KEY);
|
||||
niks.add(MagnificationJoystickPreferenceController.PREF_KEY);
|
||||
} else {
|
||||
if (!isAlwaysOnSupported(context)
|
||||
// This preference's title "Keep on while switching apps" does not
|
||||
// mention magnification so it may confuse users who search a term
|
||||
// like "Keep on".
|
||||
// So we hide it if the user has no magnification shortcut enabled.
|
||||
|| getUserShortcutTypeFromSettings(context) == DEFAULT) {
|
||||
niks.add(MagnificationAlwaysOnPreferenceController.PREF_KEY);
|
||||
}
|
||||
if (!isOneFingerPanningSupported()) {
|
||||
niks.add(MagnificationOneFingerPanningPreferenceController.PREF_KEY);
|
||||
}
|
||||
if (!isJoystickSupported()) {
|
||||
niks.add(MagnificationJoystickPreferenceController.PREF_KEY);
|
||||
}
|
||||
}
|
||||
return niks;
|
||||
}
|
||||
// LINT.ThenChange(preference_list)
|
||||
|
||||
private SearchIndexableRaw createPreferenceSearchData(
|
||||
Context context, Preference pref) {
|
||||
final SearchIndexableRaw raw = new SearchIndexableRaw(context);
|
||||
raw.key = pref.getKey();
|
||||
raw.title = pref.getTitle().toString();
|
||||
return raw;
|
||||
}
|
||||
|
||||
private SearchIndexableRaw createShortcutPreferenceSearchData(Context context) {
|
||||
final SearchIndexableRaw raw = new SearchIndexableRaw(context);
|
||||
raw.key = KEY_MAGNIFICATION_SHORTCUT_PREFERENCE;
|
||||
raw.title = context.getString(
|
||||
R.string.accessibility_screen_magnification_shortcut_title);
|
||||
return raw;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.fragment.app.Fragment
|
||||
import com.android.settings.R
|
||||
import com.android.settings.flags.Flags
|
||||
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
|
||||
import com.android.settingslib.metadata.ProvidePreferenceScreen
|
||||
import com.android.settingslib.metadata.preferenceHierarchy
|
||||
import com.android.settingslib.preference.PreferenceScreenCreator
|
||||
|
||||
/**
|
||||
* Accessibility settings for vibration intensities.
|
||||
*/
|
||||
// TODO(b/368360218): investigate if we still need this screen once we finish the migration.
|
||||
// We might be able to consolidate this into VibrationScreen with PreferenceHierarchy choosing
|
||||
// between toggle or slider preferences based on device config, depending on how overlays are done.
|
||||
// LINT.IfChange
|
||||
@ProvidePreferenceScreen
|
||||
class VibrationIntensityScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider {
|
||||
override val key: String
|
||||
get() = KEY
|
||||
|
||||
override val title: Int
|
||||
get() = R.string.accessibility_vibration_settings_title
|
||||
|
||||
override val keywords: Int
|
||||
get() = R.string.keywords_vibration
|
||||
|
||||
override fun isAvailable(context: Context) =
|
||||
context.isVibratorAvailable() && context.getSupportedVibrationIntensityLevels() > 1
|
||||
|
||||
override fun isFlagEnabled(context: Context): Boolean = Flags.catalystVibrationIntensityScreen()
|
||||
|
||||
override fun hasCompleteHierarchy() = false
|
||||
|
||||
override fun fragmentClass(): Class<out Fragment>? =
|
||||
VibrationIntensitySettingsFragment::class.java
|
||||
|
||||
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
|
||||
+VibrationMainSwitchPreference()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY = "vibration_intensity_screen"
|
||||
}
|
||||
}
|
||||
// LINT.ThenChange(VibrationPreferenceController.java)
|
||||
@@ -25,6 +25,8 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
@@ -90,4 +92,9 @@ public class VibrationIntensitySettingsFragment extends DashboardFragment {
|
||||
return VibrationIntensitySettingsFragment.isPageSearchEnabled(context);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
|
||||
return VibrationIntensityScreen.KEY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.os.VibrationAttributes
|
||||
import android.os.Vibrator
|
||||
import android.provider.Settings
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener
|
||||
import com.android.settings.R
|
||||
import com.android.settingslib.datastore.KeyValueStore
|
||||
import com.android.settingslib.datastore.KeyedObservableDelegate
|
||||
import com.android.settingslib.datastore.SettingsStore
|
||||
import com.android.settingslib.datastore.SettingsSystemStore
|
||||
import com.android.settingslib.metadata.MainSwitchPreference
|
||||
import com.android.settingslib.metadata.PreferenceLifecycleContext
|
||||
import com.android.settingslib.metadata.PreferenceLifecycleProvider
|
||||
import com.android.settingslib.metadata.ReadWritePermit
|
||||
import com.android.settingslib.preference.MainSwitchPreferenceBinding
|
||||
|
||||
/**
|
||||
* Accessibility settings for vibration.
|
||||
*/
|
||||
// LINT.IfChange
|
||||
class VibrationMainSwitchPreference : MainSwitchPreference(
|
||||
key = Settings.System.VIBRATE_ON,
|
||||
title = R.string.accessibility_vibration_primary_switch_title,
|
||||
), PreferenceLifecycleProvider, OnCheckedChangeListener {
|
||||
override val keywords: Int
|
||||
get() = R.string.keywords_accessibility_vibration_primary_switch
|
||||
|
||||
lateinit var vibrator: Vibrator
|
||||
|
||||
override fun storage(context: Context): KeyValueStore =
|
||||
VibrationMainSwitchToggleStorage(SettingsSystemStore.get(context))
|
||||
|
||||
override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) =
|
||||
ReadWritePermit.ALLOW
|
||||
|
||||
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
|
||||
ReadWritePermit.ALLOW
|
||||
|
||||
override fun onResume(context: PreferenceLifecycleContext) {
|
||||
vibrator = context.getSystemService(Vibrator::class.java)
|
||||
context.findPreference<com.android.settingslib.widget.MainSwitchPreference>(key)
|
||||
?.addOnSwitchChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onPause(context: PreferenceLifecycleContext) {
|
||||
context.findPreference<com.android.settingslib.widget.MainSwitchPreference>(key)
|
||||
?.removeOnSwitchChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onCheckedChanged(button: CompoundButton, isChecked: Boolean) {
|
||||
if (isChecked) {
|
||||
// Play a haptic as preview for the main toggle only when touch feedback is enabled.
|
||||
VibrationPreferenceConfig.playVibrationPreview(
|
||||
vibrator, VibrationAttributes.USAGE_TOUCH
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides SettingsStore for vibration main switch with custom default value. */
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private class VibrationMainSwitchToggleStorage(
|
||||
private val settingsStore: SettingsStore,
|
||||
) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
|
||||
|
||||
override fun contains(key: String) = settingsStore.contains(key)
|
||||
|
||||
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
|
||||
DEFAULT_VALUE as T
|
||||
|
||||
override fun <T : Any> getValue(key: String, valueType: Class<T>) =
|
||||
(settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T
|
||||
|
||||
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
||||
settingsStore.setBoolean(key, value as Boolean?)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_VALUE = true
|
||||
}
|
||||
}
|
||||
// LINT.ThenChange(VibrationMainSwitchPreferenceController.java)
|
||||
@@ -41,6 +41,7 @@ import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
* will disable the entire settings screen once the settings is turned OFF. All device haptics will
|
||||
* be disabled by this setting, except the flagged alerts and accessibility touch feedback.
|
||||
*/
|
||||
// LINT.IfChange
|
||||
public class VibrationMainSwitchPreferenceController extends SettingsMainSwitchPreferenceController
|
||||
implements LifecycleObserver, OnStart, OnStop {
|
||||
|
||||
@@ -106,3 +107,4 @@ public class VibrationMainSwitchPreferenceController extends SettingsMainSwitchP
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
// LINT.ThenChange(VibrationMainSwitchPreference.kt)
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
|
||||
/** Controller for "Vibration & haptics" settings page. */
|
||||
// LINT.IfChange
|
||||
public class VibrationPreferenceController extends BasePreferenceController {
|
||||
|
||||
private final boolean mHasVibrator;
|
||||
@@ -79,3 +80,7 @@ public class VibrationPreferenceController extends BasePreferenceController {
|
||||
|
||||
|
||||
}
|
||||
// LINT.ThenChange(
|
||||
// VibrationIntensityScreenTest.kt,
|
||||
// VibrationScreenTest.kt,
|
||||
// )
|
||||
|
||||
69
src/com/android/settings/accessibility/VibrationScreen.kt
Normal file
69
src/com/android/settings/accessibility/VibrationScreen.kt
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.os.Vibrator
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.android.settings.R
|
||||
import com.android.settings.flags.Flags
|
||||
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
|
||||
import com.android.settingslib.metadata.ProvidePreferenceScreen
|
||||
import com.android.settingslib.metadata.preferenceHierarchy
|
||||
import com.android.settingslib.preference.PreferenceScreenCreator
|
||||
|
||||
/**
|
||||
* Accessibility settings for vibration.
|
||||
*/
|
||||
// LINT.IfChange
|
||||
@ProvidePreferenceScreen
|
||||
class VibrationScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider {
|
||||
override val key: String
|
||||
get() = KEY
|
||||
|
||||
override val title: Int
|
||||
get() = R.string.accessibility_vibration_settings_title
|
||||
|
||||
override val keywords: Int
|
||||
get() = R.string.keywords_vibration
|
||||
|
||||
override fun isAvailable(context: Context) =
|
||||
context.isVibratorAvailable() && context.getSupportedVibrationIntensityLevels() == 1
|
||||
|
||||
override fun isFlagEnabled(context: Context): Boolean = Flags.catalystVibrationIntensityScreen()
|
||||
|
||||
override fun hasCompleteHierarchy() = false
|
||||
|
||||
override fun fragmentClass(): Class<out Fragment>? = VibrationSettings::class.java
|
||||
|
||||
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
|
||||
+VibrationMainSwitchPreference()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KEY = "vibration_screen"
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the device has a system vibrator, false otherwise. */
|
||||
fun Context.isVibratorAvailable(): Boolean =
|
||||
getSystemService(Vibrator::class.java).hasVibrator()
|
||||
|
||||
/** Returns the number of vibration intensity levels supported by this device. */
|
||||
fun Context.getSupportedVibrationIntensityLevels(): Int =
|
||||
resources.getInteger(R.integer.config_vibration_supported_intensity_levels)
|
||||
|
||||
// LINT.ThenChange(VibrationPreferenceController.java)
|
||||
@@ -20,6 +20,8 @@ import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Vibrator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -35,6 +37,11 @@ public class VibrationSettings extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "VibrationSettings";
|
||||
|
||||
@Override
|
||||
public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
|
||||
return VibrationScreen.KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCESSIBILITY_VIBRATION;
|
||||
|
||||
@@ -55,8 +55,8 @@ public class VolumeShortcutToggleAccessibilityServicePreferenceFragment extends
|
||||
final boolean isServiceOn =
|
||||
getArguments().getBoolean(AccessibilitySettings.EXTRA_CHECKED);
|
||||
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
final boolean hasRequestAccessibilityButtonFlag =
|
||||
(info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
|
||||
final boolean hasRequestAccessibilityButtonFlag = info != null
|
||||
&& (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
|
||||
if (hasRequestAccessibilityButtonFlag && isServiceOn) {
|
||||
shortcutTypes |= SOFTWARE;
|
||||
} else {
|
||||
|
||||
@@ -61,6 +61,7 @@ import com.android.internal.accessibility.dialog.AccessibilityTargetHelper;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.accessibility.AccessibilitySetupWizardUtils;
|
||||
import com.android.settings.accessibility.Flags;
|
||||
import com.android.settings.accessibility.PreferredShortcuts;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
@@ -201,9 +202,14 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
|
||||
super.onCreatePreferences(savedInstanceState, rootKey);
|
||||
|
||||
Activity activity = getActivity();
|
||||
final Preference descriptionPref = findPreference(getString(
|
||||
R.string.accessibility_shortcut_description_pref));
|
||||
|
||||
if (!activity.getIntent().getAction().equals(
|
||||
Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS)) {
|
||||
if (Flags.toggleFeatureFragmentCollectionInfo()) {
|
||||
descriptionPref.setVisible(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -219,10 +225,11 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
|
||||
);
|
||||
|
||||
activity.setTitle(titles.first);
|
||||
|
||||
String screenDescriptionPrefKey = getString(
|
||||
R.string.accessibility_shortcut_description_pref);
|
||||
findPreference(screenDescriptionPrefKey).setSummary(titles.second);
|
||||
if (titles.second != null || !Flags.toggleFeatureFragmentCollectionInfo()) {
|
||||
descriptionPref.setSummary(titles.second);
|
||||
} else {
|
||||
descriptionPref.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.os.UserHandle;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.util.ArraySet;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.Flags;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.Preference;
|
||||
@@ -82,8 +81,7 @@ public class QuickSettingsShortcutOptionController extends ShortcutOptionPrefere
|
||||
|
||||
@Override
|
||||
protected boolean isShortcutAvailable() {
|
||||
return Flags.a11yQsShortcut()
|
||||
&& TileService.isQuickSettingsSupported()
|
||||
return TileService.isQuickSettingsSupported()
|
||||
&& allTargetsHasQsTile()
|
||||
&& allTargetsHasValidQsTileUseCase();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import com.android.settings.R;
|
||||
import com.android.settingslib.widget.LottieColorUtils;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.airbnb.lottie.LottieDrawable;
|
||||
|
||||
/**
|
||||
* A preference represents an accessibility shortcut option with a checkbox and a tutorial image
|
||||
@@ -96,7 +95,8 @@ public class ShortcutOptionPreference extends CheckBoxPreference {
|
||||
.getResourceEntryName(mIntroImageRawResId),
|
||||
result));
|
||||
imageView.setAnimation(mIntroImageRawResId);
|
||||
imageView.setRepeatCount(LottieDrawable.INFINITE);
|
||||
// Follow the Motion Stoppable requirement by using a finite animation.
|
||||
imageView.setRepeatCount(0);
|
||||
LottieColorUtils.applyDynamicColors(imageView.getContext(), imageView);
|
||||
imageView.playAnimation();
|
||||
} else {
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.settings.accessibility.shortcuts;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.Flags;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.Preference;
|
||||
@@ -111,36 +110,27 @@ public abstract class ShortcutOptionPreferenceController extends BasePreferenceC
|
||||
return !targets.isEmpty() && targets.containsAll(getShortcutTargets());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable or disable the shortcut for the given accessibility features.
|
||||
*
|
||||
* @deprecated use
|
||||
* {@link AccessibilityManager#enableShortcutsForTargets(boolean, int, Set, int)} instead.
|
||||
*
|
||||
* (TODO 367414968: finish removal.)
|
||||
*/
|
||||
@Deprecated
|
||||
protected void enableShortcutForTargets(boolean enable) {
|
||||
Set<String> shortcutTargets = getShortcutTargets();
|
||||
@ShortcutConstants.UserShortcutType int shortcutType = getShortcutType();
|
||||
|
||||
if (Flags.a11yQsShortcut()) {
|
||||
AccessibilityManager a11yManager = mContext.getSystemService(
|
||||
AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(enable, shortcutType, shortcutTargets,
|
||||
UserHandle.myUserId());
|
||||
}
|
||||
return;
|
||||
AccessibilityManager a11yManager = mContext.getSystemService(
|
||||
AccessibilityManager.class);
|
||||
if (a11yManager != null) {
|
||||
a11yManager.enableShortcutsForTargets(enable, shortcutType, shortcutTargets,
|
||||
UserHandle.myUserId());
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
for (String target : shortcutTargets) {
|
||||
ShortcutUtils.optInValueToSettings(mContext, shortcutType, target);
|
||||
}
|
||||
} else {
|
||||
for (String target : shortcutTargets) {
|
||||
ShortcutUtils.optOutValueFromSettings(mContext, shortcutType, target);
|
||||
}
|
||||
}
|
||||
ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
|
||||
mContext, shortcutTargets, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the user can associate a shortcut to the targets
|
||||
*/
|
||||
|
||||
@@ -19,14 +19,11 @@ package com.android.settings.accessibility.shortcuts;
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.Flags;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityButtonFragment;
|
||||
import com.android.settings.accessibility.FloatingMenuSizePreferenceController;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.utils.AnnotationSpan;
|
||||
|
||||
@@ -62,26 +59,4 @@ public abstract class SoftwareShortcutOptionPreferenceController
|
||||
R.string.accessibility_shortcut_edit_dialog_summary_software_floating),
|
||||
linkInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enableShortcutForTargets(boolean enable) {
|
||||
super.enableShortcutForTargets(enable);
|
||||
if (Flags.a11yQsShortcut()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
// Update the A11y FAB size to large when the Magnification shortcut is enabled
|
||||
// and the user hasn't changed the floating button size
|
||||
if (isMagnificationInTargets()
|
||||
&& Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
|
||||
FloatingMenuSizePreferenceController.Size.UNKNOWN)
|
||||
== FloatingMenuSizePreferenceController.Size.UNKNOWN) {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
|
||||
FloatingMenuSizePreferenceController.Size.LARGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.Flags;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
@@ -99,17 +98,4 @@ public class TripleTapShortcutOptionController extends ShortcutOptionPreferenceC
|
||||
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
|
||||
AccessibilityUtil.State.OFF) == AccessibilityUtil.State.ON;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enableShortcutForTargets(boolean enable) {
|
||||
if (Flags.a11yQsShortcut()) {
|
||||
super.enableShortcutForTargets(enable);
|
||||
return;
|
||||
}
|
||||
|
||||
Settings.Secure.putInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
|
||||
enable ? AccessibilityUtil.State.ON : AccessibilityUtil.State.OFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,16 +86,4 @@ public class TwoFingerDoubleTapShortcutOptionController
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
|
||||
AccessibilityUtil.State.OFF) == AccessibilityUtil.State.ON;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enableShortcutForTargets(boolean enable) {
|
||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||
super.enableShortcutForTargets(enable);
|
||||
return;
|
||||
}
|
||||
Settings.Secure.putInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
|
||||
enable ? AccessibilityUtil.State.ON : AccessibilityUtil.State.OFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,12 @@
|
||||
package com.android.settings.accessibility.shortcuts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.accessibility.Flags;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil;
|
||||
|
||||
/**
|
||||
* A controller handles displaying the volume keys shortcut option preference and
|
||||
@@ -61,16 +59,4 @@ public class VolumeKeysShortcutOptionController extends ShortcutOptionPreference
|
||||
protected boolean isShortcutAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enableShortcutForTargets(boolean enable) {
|
||||
super.enableShortcutForTargets(enable);
|
||||
if (Flags.a11yQsShortcut()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
AccessibilityUtil.skipVolumeShortcutDialogTimeoutRestriction(mContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.android.settings.accounts;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AuthenticatorDescription;
|
||||
import android.content.ClipData;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
@@ -186,9 +187,9 @@ public class AccountTypePreferenceLoader {
|
||||
prefIntent, mUserHandle);
|
||||
} else {
|
||||
Log.e(TAG,
|
||||
"Refusing to launch authenticator intent because"
|
||||
+ "it exploits Settings permissions: "
|
||||
+ prefIntent);
|
||||
"Refusing to launch authenticator intent because "
|
||||
+ "it exploits Settings permissions: "
|
||||
+ prefIntent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -242,13 +243,19 @@ public class AccountTypePreferenceLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the supplied Intent is safe. A safe intent is one that is
|
||||
* will launch a exported=true activity or owned by the same uid as the
|
||||
* Determines if the supplied Intent is safe. A safe intent is one that
|
||||
* will launch an exported=true activity or owned by the same uid as the
|
||||
* authenticator supplying the intent.
|
||||
*/
|
||||
private boolean isSafeIntent(PackageManager pm, Intent intent, String acccountType) {
|
||||
@VisibleForTesting
|
||||
boolean isSafeIntent(PackageManager pm, Intent intent, String accountType) {
|
||||
if (TextUtils.equals(intent.getScheme(), ContentResolver.SCHEME_CONTENT)) {
|
||||
Log.e(TAG, "Intent with a content scheme is unsafe.");
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthenticatorDescription authDesc =
|
||||
mAuthenticatorHelper.getAccountTypeDescription(acccountType);
|
||||
mAuthenticatorHelper.getAccountTypeDescription(accountType);
|
||||
ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mUserHandle.getIdentifier());
|
||||
if (resolveInfo == null) {
|
||||
return false;
|
||||
|
||||
@@ -257,9 +257,10 @@ public class ActivityEmbeddingRulesController {
|
||||
final FingerprintEnrollActivityClassProvider fpClassProvider = FeatureFactory
|
||||
.getFeatureFactory()
|
||||
.getFingerprintFeatureProvider()
|
||||
.getEnrollActivityClassProvider();
|
||||
.getEnrollActivityClassProvider(mContext);
|
||||
addActivityFilter(activityFilters, fpClassProvider.getDefault());
|
||||
addActivityFilter(activityFilters, fpClassProvider.getInternal());
|
||||
addActivityFilter(activityFilters, fpClassProvider.getAddAnother());
|
||||
addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
|
||||
addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class);
|
||||
addActivityFilter(activityFilters, FaceEnrollIntroduction.class);
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.settings.applications;
|
||||
|
||||
import static android.webkit.Flags.updateServiceV2;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
@@ -173,11 +171,9 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
|
||||
}
|
||||
|
||||
// Keep WebView default package enabled.
|
||||
if (updateServiceV2()) {
|
||||
String packageName = mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName();
|
||||
if (packageName != null) {
|
||||
keepEnabledPackages.add(packageName);
|
||||
}
|
||||
String packageName = mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName();
|
||||
if (packageName != null) {
|
||||
keepEnabledPackages.add(packageName);
|
||||
}
|
||||
|
||||
keepEnabledPackages.addAll(getEnabledPackageAllowlist());
|
||||
|
||||
@@ -36,6 +36,7 @@ import static java.lang.Boolean.FALSE;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.compat.CompatChanges;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.LauncherApps;
|
||||
@@ -44,6 +45,7 @@ import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -71,6 +73,7 @@ public class UserAspectRatioManager {
|
||||
private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true;
|
||||
|
||||
final boolean mIsUserMinAspectRatioAppDefaultFlagEnabled = Flags.userMinAspectRatioAppDefault();
|
||||
private final boolean mIgnoreActivityOrientationRequest;
|
||||
|
||||
private final Context mContext;
|
||||
private final IPackageManager mIPm;
|
||||
@@ -90,6 +93,8 @@ public class UserAspectRatioManager {
|
||||
mUserAspectRatioA11yMap = new ArrayMap<>();
|
||||
mUserAspectRatioOrder = new SparseIntArray();
|
||||
mUserAspectRatioMap = getUserMinAspectRatioMapping();
|
||||
mIgnoreActivityOrientationRequest = getValueFromDeviceConfig(
|
||||
"ignore_activity_orientation_request", false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,6 +118,24 @@ public class UserAspectRatioManager {
|
||||
? aspectRatio : USER_MIN_ASPECT_RATIO_UNSET;
|
||||
}
|
||||
|
||||
// TODO b/374903057 reuse method from ActivityRecord
|
||||
boolean isUniversalResizeable(@NonNull String packageName, int userId) {
|
||||
try {
|
||||
final ApplicationInfo info = mIPm.getApplicationInfo(
|
||||
packageName, 0 /* flags */, userId);
|
||||
if (info == null || info.category == ApplicationInfo.CATEGORY_GAME) {
|
||||
return false;
|
||||
}
|
||||
final boolean compatEnabled = Flags.universalResizableByDefault()
|
||||
&& info.isChangeEnabled(ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT);
|
||||
return compatEnabled || mIgnoreActivityOrientationRequest;
|
||||
} catch (RemoteException e) {
|
||||
Log.e("UserAspectRatioManager", "Could not access application info for "
|
||||
+ packageName + ":\n" + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return corresponding string for {@link PackageManager.UserMinAspectRatio} value
|
||||
*/
|
||||
@@ -127,7 +150,7 @@ public class UserAspectRatioManager {
|
||||
return appDefault;
|
||||
}
|
||||
|
||||
return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio)
|
||||
return isUnsetAndRequiresFullscreenOverride(packageName, userId, aspectRatio)
|
||||
? getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName, userId)
|
||||
: mUserAspectRatioMap.getOrDefault(aspectRatio, appDefault);
|
||||
}
|
||||
@@ -139,7 +162,7 @@ public class UserAspectRatioManager {
|
||||
public CharSequence getAccessibleEntry(@PackageManager.UserMinAspectRatio int aspectRatio,
|
||||
@NonNull String packageName) {
|
||||
final int userId = mContext.getUserId();
|
||||
return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio)
|
||||
return isUnsetAndRequiresFullscreenOverride(packageName, userId, aspectRatio)
|
||||
? getAccessibleEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName)
|
||||
: mUserAspectRatioA11yMap.getOrDefault(aspectRatio,
|
||||
getUserMinAspectRatioEntry(aspectRatio, packageName, userId));
|
||||
@@ -203,7 +226,7 @@ public class UserAspectRatioManager {
|
||||
@PackageManager.UserMinAspectRatio int userOverride) {
|
||||
return (userOverride != USER_MIN_ASPECT_RATIO_UNSET
|
||||
&& userOverride != USER_MIN_ASPECT_RATIO_APP_DEFAULT)
|
||||
|| isCurrentSelectionFromManufacturerOverride(app.packageName, getUserId(app.uid),
|
||||
|| isUnsetAndRequiresFullscreenOverride(app.packageName, getUserId(app.uid),
|
||||
userOverride);
|
||||
}
|
||||
|
||||
@@ -224,7 +247,7 @@ public class UserAspectRatioManager {
|
||||
/**
|
||||
* Whether the device manufacturer has overridden app's orientation to
|
||||
* {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_USER} to force app to fullscreen
|
||||
* and app has not opted-out from the treatment
|
||||
* or app is universal resizeable, and app has not opted-out from the treatment
|
||||
*/
|
||||
boolean isOverrideToFullscreenEnabled(String pkgName, int userId) {
|
||||
Boolean appAllowsOrientationOverride = readComponentProperty(mContext.getPackageManager(),
|
||||
@@ -232,7 +255,8 @@ public class UserAspectRatioManager {
|
||||
return mIsUserMinAspectRatioAppDefaultFlagEnabled
|
||||
&& hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN, pkgName)
|
||||
&& !FALSE.equals(appAllowsOrientationOverride)
|
||||
&& isFullscreenCompatChangeEnabled(pkgName, userId);
|
||||
&& (isFullscreenCompatChangeEnabled(pkgName, userId)
|
||||
|| isUniversalResizeable(pkgName, userId));
|
||||
}
|
||||
|
||||
boolean isFullscreenCompatChangeEnabled(String pkgName, int userId) {
|
||||
@@ -240,7 +264,11 @@ public class UserAspectRatioManager {
|
||||
OVERRIDE_ANY_ORIENTATION_TO_USER, pkgName, UserHandle.of(userId));
|
||||
}
|
||||
|
||||
private boolean isCurrentSelectionFromManufacturerOverride(String pkgName, int userId,
|
||||
/**
|
||||
* Whether the aspect ratio is unset and we desire to interpret it as fullscreen rather than
|
||||
* app default because of manufacturer override or because the app is universal resizeable
|
||||
*/
|
||||
private boolean isUnsetAndRequiresFullscreenOverride(String pkgName, int userId,
|
||||
@PackageManager.UserMinAspectRatio int aspectRatio) {
|
||||
return aspectRatio == USER_MIN_ASPECT_RATIO_UNSET
|
||||
&& isOverrideToFullscreenEnabled(pkgName, userId);
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
|
||||
import com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminAdd;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.InstrumentedPreferenceFragment;
|
||||
@@ -240,13 +241,21 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
|
||||
} else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
||||
if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
|
||||
showDialogInner(ButtonActionDialogFragment.DialogType.DISABLE);
|
||||
} else if (mAppEntry.info.enabled) {
|
||||
requireAuthAndExecute(() -> {
|
||||
mMetricsFeatureProvider.action(
|
||||
mActivity,
|
||||
SettingsEnums.ACTION_SETTINGS_DISABLE_APP,
|
||||
getPackageNameForMetric());
|
||||
AsyncTask.execute(new DisableChangerRunnable(mPm,
|
||||
mAppEntry.info.packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT));
|
||||
});
|
||||
} else {
|
||||
mMetricsFeatureProvider.action(
|
||||
mActivity,
|
||||
mAppEntry.info.enabled
|
||||
? SettingsEnums.ACTION_SETTINGS_DISABLE_APP
|
||||
: SettingsEnums.ACTION_SETTINGS_ENABLE_APP,
|
||||
getPackageNameForMetric());
|
||||
SettingsEnums.ACTION_SETTINGS_ENABLE_APP,
|
||||
getPackageNameForMetric());
|
||||
AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT));
|
||||
}
|
||||
@@ -289,17 +298,34 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given action with restricted lock authentication if it is a protected package.
|
||||
*
|
||||
* @param action The action to run.
|
||||
*/
|
||||
private void requireAuthAndExecute(Runnable action) {
|
||||
if (Utils.isProtectedPackage(mContext, mAppEntry.info.packageName)) {
|
||||
AppInfoDashboardFragment.showLockScreen(mContext, () -> action.run());
|
||||
} else {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void handleDialogClick(int id) {
|
||||
switch (id) {
|
||||
case ButtonActionDialogFragment.DialogType.DISABLE:
|
||||
mMetricsFeatureProvider.action(mActivity,
|
||||
SettingsEnums.ACTION_SETTINGS_DISABLE_APP,
|
||||
getPackageNameForMetric());
|
||||
AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER));
|
||||
requireAuthAndExecute(() -> {
|
||||
mMetricsFeatureProvider.action(mActivity,
|
||||
SettingsEnums.ACTION_SETTINGS_DISABLE_APP,
|
||||
getPackageNameForMetric());
|
||||
AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER));
|
||||
});
|
||||
break;
|
||||
case ButtonActionDialogFragment.DialogType.FORCE_STOP:
|
||||
forceStopPackage(mAppEntry.info.packageName);
|
||||
requireAuthAndExecute(() -> {
|
||||
forceStopPackage(mAppEntry.info.packageName);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -535,14 +561,16 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
|
||||
|
||||
@VisibleForTesting
|
||||
void uninstallPkg(String packageName, boolean allUsers) {
|
||||
stopListeningToPackageRemove();
|
||||
// Create new intent to launch Uninstaller activity
|
||||
Uri packageUri = Uri.parse("package:" + packageName);
|
||||
Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
|
||||
uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
|
||||
requireAuthAndExecute(() -> {
|
||||
stopListeningToPackageRemove();
|
||||
// Create new intent to launch Uninstaller activity
|
||||
Uri packageUri = Uri.parse("package:" + packageName);
|
||||
Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
|
||||
uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
|
||||
|
||||
mMetricsFeatureProvider.action(mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP);
|
||||
mFragment.startActivityForResult(uninstallIntent, mRequestUninstall);
|
||||
mMetricsFeatureProvider.action(mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP);
|
||||
mFragment.startActivityForResult(uninstallIntent, mRequestUninstall);
|
||||
});
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications.appinfo;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.flags.Flags;
|
||||
|
||||
/**
|
||||
* A controller to update current locale information of application
|
||||
* and a entry to launch {@link ManageApplications}.
|
||||
*/
|
||||
public class AppsLocalePreferenceController extends BasePreferenceController {
|
||||
public AppsLocalePreferenceController(@NonNull Context context, @NonNull String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (!Flags.regionalPreferencesApiEnabled()) {
|
||||
return AVAILABLE;
|
||||
}
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ package com.android.settings.applications.appinfo;
|
||||
|
||||
import static android.app.Activity.RESULT_CANCELED;
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
|
||||
import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
@@ -34,6 +36,7 @@ import com.android.settings.Settings;
|
||||
import com.android.settings.applications.AppInfoWithHeader;
|
||||
import com.android.settings.applications.AppStateInstallAppsBridge;
|
||||
import com.android.settings.applications.AppStateInstallAppsBridge.InstallAppsState;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.RestrictedSwitchPreference;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
|
||||
@@ -82,15 +85,34 @@ public class ExternalSourcesDetails extends AppInfoWithHeader
|
||||
public static CharSequence getPreferenceSummary(Context context, AppEntry entry) {
|
||||
final UserHandle userHandle = UserHandle.getUserHandleForUid(entry.info.uid);
|
||||
final UserManager um = UserManager.get(context);
|
||||
final int userRestrictionSource = um.getUserRestrictionSource(
|
||||
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle)
|
||||
| um.getUserRestrictionSource(
|
||||
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
|
||||
userHandle);
|
||||
if ((userRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
|
||||
return context.getString(com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
|
||||
} else if (userRestrictionSource != 0) {
|
||||
return context.getString(com.android.settingslib.R.string.disabled);
|
||||
if (android.security.Flags.aapmFeatureDisableInstallUnknownSources()) {
|
||||
if (um.hasBaseUserRestriction(DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle)) {
|
||||
return context.getString(com.android.settingslib.R.string.disabled);
|
||||
} else if (um.hasUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle)) {
|
||||
return context.getString(
|
||||
com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
|
||||
} else if (um.hasUserRestrictionForUser(DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
|
||||
userHandle)) {
|
||||
if (RestrictedLockUtilsInternal.isPolicyEnforcedByAdvancedProtection(context,
|
||||
DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userHandle.getIdentifier())) {
|
||||
return context.getString(com.android.settingslib.widget.restricted
|
||||
.R.string.disabled_by_advanced_protection);
|
||||
} else {
|
||||
return context.getString(
|
||||
com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final int userRestrictionSource = um.getUserRestrictionSource(
|
||||
DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle)
|
||||
| um.getUserRestrictionSource(
|
||||
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, userHandle);
|
||||
if ((userRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
|
||||
return context.getString(
|
||||
com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
|
||||
} else if (userRestrictionSource != 0) {
|
||||
return context.getString(com.android.settingslib.R.string.disabled);
|
||||
}
|
||||
}
|
||||
final InstallAppsState appsState = new AppStateInstallAppsBridge(context, null, null)
|
||||
.createInstallAppsStateFor(entry.info.packageName, entry.info.uid);
|
||||
@@ -110,14 +132,14 @@ public class ExternalSourcesDetails extends AppInfoWithHeader
|
||||
if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
|
||||
return false;
|
||||
}
|
||||
if (mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
|
||||
if (mUserManager.hasBaseUserRestriction(DISALLOW_INSTALL_UNKNOWN_SOURCES,
|
||||
UserHandle.of(UserHandle.myUserId()))) {
|
||||
mSwitchPref.setChecked(false);
|
||||
mSwitchPref.setSummary(com.android.settingslib.R.string.disabled);
|
||||
mSwitchPref.setEnabled(false);
|
||||
return true;
|
||||
}
|
||||
mSwitchPref.checkRestrictionAndSetDisabled(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
|
||||
mSwitchPref.checkRestrictionAndSetDisabled(DISALLOW_INSTALL_UNKNOWN_SOURCES);
|
||||
if (!mSwitchPref.isDisabledByAdmin()) {
|
||||
mSwitchPref.checkRestrictionAndSetDisabled(
|
||||
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications.appinfo;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.flags.Flags;
|
||||
|
||||
/**
|
||||
* A controller to update current locale information of application
|
||||
* and a entry to launch {@link ManageApplications}.
|
||||
*/
|
||||
public class NewAppsLocalePreferenceController extends BasePreferenceController {
|
||||
|
||||
public NewAppsLocalePreferenceController(@NonNull Context context, @NonNull String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
// TODO(b/381011808) After feature release, this class may be renamed.
|
||||
if (Flags.regionalPreferencesApiEnabled()) {
|
||||
return AVAILABLE;
|
||||
}
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.applications.contacts;
|
||||
|
||||
import static android.provider.ContactsContract.RawContacts.DefaultAccount;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
|
||||
import android.provider.Flags;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.accounts.AuthenticatorHelper;
|
||||
|
||||
/**
|
||||
* A preference controller handling the logic for updating summary of contacts default account.
|
||||
*/
|
||||
public class ContactsStoragePreferenceController extends BasePreferenceController {
|
||||
private static final String TAG = "ContactsStorageController";
|
||||
|
||||
private final AuthenticatorHelper mAuthenticatorHelper;
|
||||
|
||||
private DefaultAccountAndState mCurrentDefaultAccountAndState;
|
||||
|
||||
public ContactsStoragePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mAuthenticatorHelper = new AuthenticatorHelper(mContext,
|
||||
new UserHandle(UserHandle.myUserId()), null);
|
||||
try {
|
||||
mCurrentDefaultAccountAndState =
|
||||
DefaultAccount.getDefaultAccountForNewContacts(mContext.getContentResolver());
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "The default account is in an invalid state: " + e);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Failed to look up the default account: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return (Flags.newDefaultAccountApiEnabled()
|
||||
&& mCurrentDefaultAccountAndState != null) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
if (mCurrentDefaultAccountAndState != null) {
|
||||
// Re-fetch account in controller to refresh the latest set default account.
|
||||
mCurrentDefaultAccountAndState =
|
||||
DefaultAccount.getDefaultAccountForNewContacts(mContext.getContentResolver());
|
||||
int currentDefaultAccountState = mCurrentDefaultAccountAndState.getState();
|
||||
Account currentDefaultAccount = mCurrentDefaultAccountAndState.getAccount();
|
||||
if (currentDefaultAccountState
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET) {
|
||||
return mContext.getResources().getString(
|
||||
R.string.contacts_storage_no_account_set_summary);
|
||||
} else if (currentDefaultAccountState
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL) {
|
||||
return mContext.getResources().getString(
|
||||
R.string.contacts_storage_local_account_summary);
|
||||
} else if (currentDefaultAccountState
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM) {
|
||||
return mContext.getResources().getString(
|
||||
R.string.sim_card_label);
|
||||
} else if (currentDefaultAccountState
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
|
||||
String accountTypeLabel = (String) mAuthenticatorHelper.getLabelForType(mContext,
|
||||
currentDefaultAccount.type);
|
||||
// If there's no account type, or the account type is the same as the
|
||||
// current default account name, just return the account name.
|
||||
if (accountTypeLabel == null || accountTypeLabel.equals(
|
||||
currentDefaultAccount.name)) {
|
||||
return currentDefaultAccount.name;
|
||||
}
|
||||
return accountTypeLabel + " | " + currentDefaultAccount.name;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.applications.contacts;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.provider.ContactsContract.RawContacts.DefaultAccount;
|
||||
import static android.provider.Settings.ACTION_ADD_ACCOUNT;
|
||||
import static android.provider.Settings.EXTRA_ACCOUNT_TYPES;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.Preference.OnPreferenceClickListener;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accounts.AddAccountSettings;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
import com.android.settingslib.accounts.AuthenticatorHelper;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.widget.SelectorWithWidgetPreference;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Settings page for contacts default account
|
||||
*/
|
||||
@SearchIndexable
|
||||
public class ContactsStorageSettings extends DashboardFragment
|
||||
implements SelectorWithWidgetPreference.OnClickListener, OnPreferenceClickListener,
|
||||
AuthenticatorHelper.OnAccountsUpdateListener {
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.contacts_storage_settings);
|
||||
private static final String TAG = "ContactsStorageSettings";
|
||||
private static final String PREF_KEY_ADD_ACCOUNT = "add_account";
|
||||
private static final String PREF_KEY_DEVICE_ONLY = "device_only_account_preference";
|
||||
private static final String PREF_KEY_ACCOUNT_CATEGORY = "account_category";
|
||||
private final Map<String, DefaultAccountAndState> mAccountMap = new HashMap<>();
|
||||
private AuthenticatorHelper mAuthenticatorHelper;
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
mAuthenticatorHelper = new AuthenticatorHelper(context,
|
||||
new UserHandle(UserHandle.myUserId()), this);
|
||||
mAuthenticatorHelper.listenToAccountUpdates();
|
||||
preloadEligibleAccountIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mAuthenticatorHelper.stopListeningToAccountUpdates();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void onRadioButtonClicked(@NonNull SelectorWithWidgetPreference selectedPref) {
|
||||
final String selectedPreferenceKey = selectedPref.getKey();
|
||||
// Check if current account is different from the selected account.
|
||||
for (String preferenceKey : mAccountMap.keySet()) {
|
||||
if (selectedPreferenceKey.equals(preferenceKey)) {
|
||||
try {
|
||||
DefaultAccountAndState currentDefaultAccount = mAccountMap.get(preferenceKey);
|
||||
DefaultAccount.setDefaultAccountForNewContacts(getContentResolver(),
|
||||
currentDefaultAccount);
|
||||
selectedPref.setChecked(true);
|
||||
if (currentDefaultAccount.getState()
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
|
||||
startMoveLocalAndSimContactsActivity();
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Error setting the default account " + e);
|
||||
Toast.makeText(getContext(),
|
||||
R.string.contacts_storage_set_default_account_error_message,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
SelectorWithWidgetPreference unSelectedPreference =
|
||||
getPreferenceScreen().findPreference(preferenceKey);
|
||||
if (unSelectedPreference != null) {
|
||||
unSelectedPreference.setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onPreferenceClick(@NonNull Preference preference) {
|
||||
if (PREF_KEY_ADD_ACCOUNT.equals(preference.getKey())) {
|
||||
String[] accountTypesArray = getEligibleAccountTypes();
|
||||
Intent intent = new Intent(ACTION_ADD_ACCOUNT);
|
||||
intent.setClass(getContext(), AddAccountSettings.class);
|
||||
intent.putExtra(EXTRA_ACCOUNT_TYPES, accountTypesArray);
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
getContext().startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccountsUpdate(UserHandle userHandle) {
|
||||
preloadEligibleAccountIcon();
|
||||
refreshUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(@NonNull Bundle savedInstanceState,
|
||||
@NonNull String rootKey) {
|
||||
super.onCreatePreferences(savedInstanceState, rootKey);
|
||||
refreshUI();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
void refreshUI() {
|
||||
// Clear all the accounts stored in the map and later on re-fetch the eligible accounts
|
||||
// when creating eligible account preferences.
|
||||
mAccountMap.clear();
|
||||
final PreferenceGroup preferenceGroup = findPreference(PREF_KEY_ACCOUNT_CATEGORY);
|
||||
preferenceGroup.removeAll();
|
||||
// If the default account is SIM, we should show in the page, otherwise don't show.
|
||||
SelectorWithWidgetPreference simAccountPreference = buildSimAccountPreference();
|
||||
if (simAccountPreference != null) {
|
||||
preferenceGroup.addPreference(simAccountPreference);
|
||||
}
|
||||
List<Account> accounts = DefaultAccount.getEligibleCloudAccounts(getContentResolver());
|
||||
for (int i = 0; i < accounts.size(); i++) {
|
||||
preferenceGroup.addPreference(
|
||||
buildCloudAccountPreference(accounts.get(i), /*order=*/i));
|
||||
}
|
||||
// If there's no eligible account types, the "Add Account" preference should
|
||||
// not be shown to the users.
|
||||
if (getEligibleAccountTypes().length > 0) {
|
||||
preferenceGroup.addPreference(buildAddAccountPreference(accounts.isEmpty()));
|
||||
}
|
||||
setupDeviceOnlyPreference();
|
||||
setDefaultAccountPreference(preferenceGroup);
|
||||
}
|
||||
|
||||
private void preloadEligibleAccountIcon() {
|
||||
String[] accountTypes = getEligibleAccountTypes();
|
||||
for (String accountType : accountTypes) {
|
||||
// Preload the drawable for the account type to avoid the latency when rendering the
|
||||
// account preference.
|
||||
mAuthenticatorHelper.preloadDrawableForType(getContext(), accountType);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDeviceOnlyPreference() {
|
||||
SelectorWithWidgetPreference preference = findPreference(PREF_KEY_DEVICE_ONLY);
|
||||
if (preference != null) {
|
||||
preference.setOnClickListener(this);
|
||||
mAccountMap.put(PREF_KEY_DEVICE_ONLY, DefaultAccountAndState.ofLocal());
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultAccountPreference(PreferenceGroup preferenceGroup) {
|
||||
DefaultAccountAndState currentDefaultAccountAndState =
|
||||
DefaultAccount.getDefaultAccountForNewContacts(getContentResolver());
|
||||
String preferenceKey = getAccountHashCode(currentDefaultAccountAndState);
|
||||
Account currentDefaultAccount = currentDefaultAccountAndState.getAccount();
|
||||
|
||||
// Set the current default account preference to be checked if found among existing
|
||||
// preferences. If not, then create a new preference for default account.
|
||||
SelectorWithWidgetPreference preference = null;
|
||||
if (mAccountMap.containsKey(preferenceKey)) {
|
||||
preference = getPreferenceScreen().findPreference(preferenceKey);
|
||||
} else if (preferenceKey != null && currentDefaultAccount != null) {
|
||||
preference = buildCloudAccountPreference(currentDefaultAccount, mAccountMap.size());
|
||||
preferenceGroup.addPreference(preference);
|
||||
}
|
||||
if (preference != null) {
|
||||
preference.setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
private SelectorWithWidgetPreference buildCloudAccountPreference(Account account, int order) {
|
||||
SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(
|
||||
getPrefContext());
|
||||
DefaultAccountAndState accountAndState = DefaultAccountAndState.ofCloud(account);
|
||||
String preferenceKey = getAccountHashCode(accountAndState);
|
||||
String accountPreferenceTitle = getString(R.string.contacts_storage_account_title,
|
||||
mAuthenticatorHelper.getLabelForType(getPrefContext(), account.type));
|
||||
preference.setTitle(accountPreferenceTitle);
|
||||
preference.setIcon(mAuthenticatorHelper.getDrawableForType(getPrefContext(), account.type));
|
||||
preference.setSummary(account.name);
|
||||
preference.setKey(preferenceKey);
|
||||
preference.setOnClickListener(this);
|
||||
preference.setOrder(order);
|
||||
mAccountMap.put(preferenceKey, accountAndState);
|
||||
return preference;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SelectorWithWidgetPreference buildSimAccountPreference() {
|
||||
DefaultAccountAndState currentDefaultAccountAndState =
|
||||
DefaultAccount.getDefaultAccountForNewContacts(getContentResolver());
|
||||
if (currentDefaultAccountAndState.getState()
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM) {
|
||||
String preferenceKey = getAccountHashCode(currentDefaultAccountAndState);
|
||||
SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(
|
||||
getPrefContext());
|
||||
preference.setTitle(R.string.sim_card_label);
|
||||
preference.setIcon(R.drawable.ic_sim_card);
|
||||
preference.setSummary(R.string.sim_card_label);
|
||||
preference.setKey(preferenceKey);
|
||||
preference.setOnClickListener(this);
|
||||
mAccountMap.put(preferenceKey, currentDefaultAccountAndState);
|
||||
return preference;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private RestrictedPreference buildAddAccountPreference(boolean noAccountBeenAdded) {
|
||||
RestrictedPreference preference = new RestrictedPreference(getPrefContext());
|
||||
preference.setKey(PREF_KEY_ADD_ACCOUNT);
|
||||
if (noAccountBeenAdded) {
|
||||
preference.setTitle(R.string.contacts_storage_first_time_add_account_message);
|
||||
} else {
|
||||
preference.setTitle(R.string.add_account_label);
|
||||
}
|
||||
preference.setIcon(R.drawable.ic_add_24dp);
|
||||
preference.setOnPreferenceClickListener(this);
|
||||
preference.setOrder(998);
|
||||
return preference;
|
||||
}
|
||||
|
||||
private void startMoveLocalAndSimContactsActivity() {
|
||||
Intent intent = new Intent()
|
||||
.setAction(DefaultAccount.ACTION_MOVE_CONTACTS_TO_DEFAULT_ACCOUNT)
|
||||
.setPackage("com.android.providers.contacts")
|
||||
.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
getContext().startActivity(intent);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getAccountHashCode(
|
||||
DefaultAccountAndState currentDefaultAccountAndState) {
|
||||
Account currentDefaultAccount = currentDefaultAccountAndState.getAccount();
|
||||
if (currentDefaultAccount != null && (currentDefaultAccountAndState.getState()
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD
|
||||
|| currentDefaultAccountAndState.getState()
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM)) {
|
||||
return String.valueOf(currentDefaultAccount.hashCode());
|
||||
} else if (currentDefaultAccountAndState.getState()
|
||||
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL) {
|
||||
return PREF_KEY_DEVICE_ONLY;
|
||||
} else {
|
||||
// If the account is not set or in error state, it should just return null and won't
|
||||
// set the checked status in radio button.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String[] getEligibleAccountTypes() {
|
||||
return Resources.getSystem().getStringArray(
|
||||
com.android.internal.R.array.config_rawContactsEligibleDefaultAccountTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.contacts_storage_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.CONTACTS_STORAGE;
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,10 @@ import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.Indexable;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
@@ -46,13 +46,16 @@ import java.util.List;
|
||||
* Therefore, as a simple workaround, we use a new class which is enabled by default.
|
||||
*/
|
||||
@SearchIndexable
|
||||
public class UserBackupSettingsActivity extends FragmentActivity implements Indexable {
|
||||
public class UserBackupSettingsActivity extends SettingsActivity implements Indexable {
|
||||
private static final String TAG = "BackupSettingsActivity";
|
||||
private FragmentManager mFragmentManager;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (isFinishing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BackupSettingsHelper backupHelper = new BackupSettingsHelper(this);
|
||||
|
||||
|
||||
@@ -148,8 +148,16 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTheme(SetupWizardUtils.getTheme(this, getIntent()));
|
||||
ThemeHelper.trySetDynamicColor(this);
|
||||
|
||||
if (ThemeHelper.shouldApplyGlifExpressiveStyle(getApplicationContext())) {
|
||||
if (!ThemeHelper.trySetSuwTheme(this)) {
|
||||
setTheme(ThemeHelper.getSuwDefaultTheme(getApplicationContext()));
|
||||
ThemeHelper.trySetDynamicColor(this);
|
||||
}
|
||||
} else {
|
||||
setTheme(SetupWizardUtils.getTheme(this, getIntent()));
|
||||
ThemeHelper.trySetDynamicColor(this);
|
||||
}
|
||||
mChallenge = getIntent().getLongExtra(EXTRA_KEY_CHALLENGE, -1L);
|
||||
mSensorId = getIntent().getIntExtra(EXTRA_KEY_SENSOR_ID, -1);
|
||||
// Don't need to retrieve the HAT if it already exists. In some cases, the extras do not
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settings.password.ChooseLockGeneric;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.password.ConfirmDeviceCredentialActivity;
|
||||
@@ -551,8 +552,11 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
@NonNull
|
||||
protected PorterDuffColorFilter getIconColorFilter() {
|
||||
if (mIconColorFilter == null) {
|
||||
final int colorType = Flags.biometricsOnboardingEducation()
|
||||
? DynamicColorPalette.ColorType.PRIMARY_TEXT
|
||||
: DynamicColorPalette.ColorType.ACCENT;
|
||||
mIconColorFilter = new PorterDuffColorFilter(
|
||||
DynamicColorPalette.getColor(this, DynamicColorPalette.ColorType.ACCENT),
|
||||
DynamicColorPalette.getColor(this, colorType),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
return mIconColorFilter;
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.android.settings.biometrics.BiometricEnrollActivity;
|
||||
import com.android.settings.biometrics.BiometricEnrollIntroduction;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.biometrics.MultiBiometricEnrollHelper;
|
||||
import com.android.settings.flags.Flags;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.password.SetupSkipDialog;
|
||||
import com.android.settings.utils.SensorPrivacyManagerHelper;
|
||||
@@ -144,6 +145,19 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
final ImageView iconLooking = findViewById(R.id.icon_looking);
|
||||
iconGlasses.getBackground().setColorFilter(getIconColorFilter());
|
||||
iconLooking.getBackground().setColorFilter(getIconColorFilter());
|
||||
if (Flags.biometricsOnboardingEducation()) {
|
||||
final ImageView iconSecurityPrivacySafe = findViewById(R.id.icon_security_privacy_safe);
|
||||
final ImageView iconPrivacyTip = findViewById(R.id.icon_privacy_tip);
|
||||
final ImageView iconFamiliarFaceAndZone =
|
||||
findViewById(R.id.icon_familiar_face_and_zone);
|
||||
final ImageView iconTrashCan = findViewById(R.id.icon_trash_can);
|
||||
final ImageView iconLink = findViewById(R.id.icon_link);
|
||||
iconSecurityPrivacySafe.getBackground().setColorFilter(getIconColorFilter());
|
||||
iconPrivacyTip.getBackground().setColorFilter(getIconColorFilter());
|
||||
iconFamiliarFaceAndZone.getBackground().setColorFilter(getIconColorFilter());
|
||||
iconTrashCan.getBackground().setColorFilter(getIconColorFilter());
|
||||
iconLink.getBackground().setColorFilter(getIconColorFilter());
|
||||
}
|
||||
|
||||
// Set text for views with multiple variations.
|
||||
final TextView infoMessageGlasses = findViewById(R.id.info_message_glasses);
|
||||
@@ -156,9 +170,19 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
infoMessageLooking.setText(getInfoMessageLooking());
|
||||
inControlTitle.setText(getInControlTitle());
|
||||
howMessage.setText(getHowMessage());
|
||||
inControlMessage.setText(Html.fromHtml(getString(getInControlMessage()),
|
||||
Html.FROM_HTML_MODE_LEGACY));
|
||||
inControlMessage.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
if (Flags.biometricsOnboardingEducation()) {
|
||||
inControlMessage.setText(
|
||||
R.string.security_settings_face_enroll_introduction_control_message_2);
|
||||
final TextView learnMore = findViewById(R.id.message_learn_more);
|
||||
learnMore.setText(Html.fromHtml(getString(
|
||||
R.string.security_settings_face_enroll_introduction_learn_more_message),
|
||||
Html.FROM_HTML_MODE_LEGACY));
|
||||
learnMore.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
} else {
|
||||
inControlMessage.setText(Html.fromHtml(getString(getInControlMessage()),
|
||||
Html.FROM_HTML_MODE_LEGACY));
|
||||
inControlMessage.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
lessSecure.setText(getLessSecureMessage());
|
||||
|
||||
final ScrollView scrollView =
|
||||
@@ -411,7 +435,11 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
@Override
|
||||
protected int getLayoutResource() {
|
||||
return R.layout.face_enroll_introduction;
|
||||
if (Flags.biometricsOnboardingEducation()) {
|
||||
return R.layout.face_enroll_introduction_2;
|
||||
} else {
|
||||
return R.layout.face_enroll_introduction;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -594,8 +622,13 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
setDescriptionText(getString(
|
||||
R.string.private_space_face_enroll_introduction_message));
|
||||
} else if (mIsFaceStrong) {
|
||||
setDescriptionText(getString(
|
||||
R.string.security_settings_face_enroll_introduction_message_class3));
|
||||
final int messageRes;
|
||||
if (Flags.biometricsOnboardingEducation()) {
|
||||
messageRes = R.string.security_settings_face_enroll_introduction_message_class3_2;
|
||||
} else {
|
||||
messageRes = R.string.security_settings_face_enroll_introduction_message_class3;
|
||||
}
|
||||
setDescriptionText(getString(messageRes));
|
||||
}
|
||||
super.updateDescriptionText();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user