Merge tm-dev-plus-aosp-without-vendor@8763363
Bug: 236760014 Merged-In: Ifcb9d4c564839199d998bd503f390f021c6bf3ad Change-Id: I9d69bcbc6916176beece2616f152ebd3d74fc0f8
This commit is contained in:
65
src/com/android/settings/ActionDisabledByAppOpsDialog.java
Normal file
65
src/com/android/settings/ActionDisabledByAppOpsDialog.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
public class ActionDisabledByAppOpsDialog extends Activity
|
||||
implements DialogInterface.OnDismissListener {
|
||||
|
||||
private static final String TAG = "ActionDisabledByAppOpsDialog";
|
||||
|
||||
private ActionDisabledByAppOpsHelper mDialogHelper;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mDialogHelper = new ActionDisabledByAppOpsHelper(this);
|
||||
mDialogHelper.prepareDialogBuilder()
|
||||
.setOnDismissListener(this)
|
||||
.show();
|
||||
updateAppOps();
|
||||
}
|
||||
|
||||
private void updateAppOps() {
|
||||
final Intent intent = getIntent();
|
||||
final String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
|
||||
final int uid = intent.getIntExtra(Intent.EXTRA_UID, android.os.Process.INVALID_UID);
|
||||
getSystemService(AppOpsManager.class)
|
||||
.setMode(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
|
||||
uid,
|
||||
packageName,
|
||||
AppOpsManager.MODE_IGNORED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
mDialogHelper.updateDialog();
|
||||
updateAppOps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
88
src/com/android/settings/ActionDisabledByAppOpsHelper.java
Normal file
88
src/com/android/settings/ActionDisabledByAppOpsHelper.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settingslib.HelpUtils;
|
||||
|
||||
final class ActionDisabledByAppOpsHelper {
|
||||
|
||||
private final ViewGroup mDialogView;
|
||||
private final Activity mActivity;
|
||||
|
||||
ActionDisabledByAppOpsHelper(Activity activity) {
|
||||
mActivity = activity;
|
||||
mDialogView = (ViewGroup) LayoutInflater.from(mActivity).inflate(
|
||||
R.layout.support_details_dialog, null);
|
||||
}
|
||||
|
||||
public AlertDialog.Builder prepareDialogBuilder() {
|
||||
final String helpUrl = mActivity.getString(
|
||||
R.string.help_url_action_disabled_by_restricted_settings);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity)
|
||||
.setPositiveButton(R.string.okay, null)
|
||||
.setView(mDialogView);
|
||||
if (!TextUtils.isEmpty(helpUrl)) {
|
||||
builder.setNeutralButton(R.string.learn_more,
|
||||
(DialogInterface.OnClickListener) (dialog, which) -> {
|
||||
final Intent intent = HelpUtils.getHelpIntent(mActivity,
|
||||
helpUrl, mActivity.getClass().getName());
|
||||
if (intent != null) {
|
||||
mActivity.startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
initializeDialogViews(mDialogView);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public void updateDialog() {
|
||||
initializeDialogViews(mDialogView);
|
||||
}
|
||||
|
||||
private void initializeDialogViews(View root) {
|
||||
setSupportTitle(root);
|
||||
setSupportDetails(root);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setSupportTitle(View root) {
|
||||
final TextView titleView = root.findViewById(R.id.admin_support_dialog_title);
|
||||
if (titleView == null) {
|
||||
return;
|
||||
}
|
||||
titleView.setText(R.string.blocked_by_restricted_settings_title);
|
||||
}
|
||||
|
||||
void setSupportDetails(final View root) {
|
||||
final TextView textView = root.findViewById(R.id.admin_support_msg);
|
||||
textView.setText(R.string.blocked_by_restricted_settings_content);
|
||||
}
|
||||
}
|
||||
@@ -59,25 +59,25 @@ import java.util.List;
|
||||
*/
|
||||
public class ActivityPicker extends AlertActivity implements
|
||||
DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
|
||||
|
||||
|
||||
/**
|
||||
* Adapter of items that are displayed in this dialog.
|
||||
*/
|
||||
private PickAdapter mAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* Base {@link Intent} used when building list.
|
||||
*/
|
||||
private Intent mBaseIntent;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
|
||||
|
||||
final Intent intent = getIntent();
|
||||
|
||||
|
||||
// Read base intent from extras, otherwise assume default
|
||||
Parcelable parcel = intent.getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
if (parcel instanceof Intent) {
|
||||
@@ -95,14 +95,14 @@ public class ActivityPicker extends AlertActivity implements
|
||||
AlertController.AlertParams params = mAlertParams;
|
||||
params.mOnClickListener = this;
|
||||
params.mOnCancelListener = this;
|
||||
|
||||
|
||||
// Use custom title if provided, otherwise default window title
|
||||
if (intent.hasExtra(Intent.EXTRA_TITLE)) {
|
||||
params.mTitle = intent.getStringExtra(Intent.EXTRA_TITLE);
|
||||
} else {
|
||||
params.mTitle = getTitle();
|
||||
}
|
||||
|
||||
|
||||
// Build list adapter of pickable items
|
||||
List<PickAdapter.Item> items = getItems();
|
||||
mAdapter = new PickAdapter(this, items);
|
||||
@@ -110,7 +110,7 @@ public class ActivityPicker extends AlertActivity implements
|
||||
|
||||
setupAlert();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle clicking of dialog item by passing back
|
||||
* {@link #getIntentForPosition(int)} in {@link #setResult(int, Intent)}.
|
||||
@@ -120,7 +120,7 @@ public class ActivityPicker extends AlertActivity implements
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle canceled dialog by passing back {@link Activity#RESULT_CANCELED}.
|
||||
*/
|
||||
@@ -148,19 +148,19 @@ public class ActivityPicker extends AlertActivity implements
|
||||
protected List<PickAdapter.Item> getItems() {
|
||||
PackageManager packageManager = getPackageManager();
|
||||
List<PickAdapter.Item> items = new ArrayList<PickAdapter.Item>();
|
||||
|
||||
|
||||
// Add any injected pick items
|
||||
final Intent intent = getIntent();
|
||||
ArrayList<String> labels =
|
||||
intent.getStringArrayListExtra(Intent.EXTRA_SHORTCUT_NAME);
|
||||
ArrayList<ShortcutIconResource> icons =
|
||||
intent.getParcelableArrayListExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
|
||||
|
||||
|
||||
if (labels != null && icons != null && labels.size() == icons.size()) {
|
||||
for (int i = 0; i < labels.size(); i++) {
|
||||
String label = labels.get(i);
|
||||
Drawable icon = null;
|
||||
|
||||
|
||||
try {
|
||||
// Try loading icon from requested package
|
||||
ShortcutIconResource iconResource = icons.get(i);
|
||||
@@ -171,7 +171,7 @@ public class ActivityPicker extends AlertActivity implements
|
||||
} catch (NameNotFoundException e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
|
||||
items.add(new PickAdapter.Item(this, label, icon));
|
||||
}
|
||||
}
|
||||
@@ -180,38 +180,38 @@ public class ActivityPicker extends AlertActivity implements
|
||||
if (mBaseIntent != null) {
|
||||
putIntentItems(mBaseIntent, items);
|
||||
}
|
||||
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the given list with any activities matching the base {@link Intent}.
|
||||
* Fill the given list with any activities matching the base {@link Intent}.
|
||||
*/
|
||||
protected void putIntentItems(Intent baseIntent, List<PickAdapter.Item> items) {
|
||||
PackageManager packageManager = getPackageManager();
|
||||
List<ResolveInfo> list = packageManager.queryIntentActivities(baseIntent,
|
||||
0 /* no flags */);
|
||||
Collections.sort(list, new ResolveInfo.DisplayNameComparator(packageManager));
|
||||
|
||||
|
||||
final int listSize = list.size();
|
||||
for (int i = 0; i < listSize; i++) {
|
||||
ResolveInfo resolveInfo = list.get(i);
|
||||
items.add(new PickAdapter.Item(this, packageManager, resolveInfo));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapter which shows the set of activities that can be performed for a
|
||||
* given {@link Intent}.
|
||||
*/
|
||||
protected static class PickAdapter extends BaseAdapter {
|
||||
|
||||
|
||||
/**
|
||||
* Item that appears in a {@link PickAdapter} list.
|
||||
*/
|
||||
public static class Item implements AppWidgetLoader.LabelledItem {
|
||||
protected static IconResizer sResizer;
|
||||
|
||||
|
||||
protected IconResizer getResizer(Context context) {
|
||||
if (sResizer == null) {
|
||||
final Resources resources = context.getResources();
|
||||
@@ -220,13 +220,13 @@ public class ActivityPicker extends AlertActivity implements
|
||||
}
|
||||
return sResizer;
|
||||
}
|
||||
|
||||
|
||||
CharSequence label;
|
||||
Drawable icon;
|
||||
String packageName;
|
||||
String className;
|
||||
Bundle extras;
|
||||
|
||||
|
||||
/**
|
||||
* Create a list item from given label and icon.
|
||||
*/
|
||||
@@ -275,10 +275,10 @@ public class ActivityPicker extends AlertActivity implements
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final List<Item> mItems;
|
||||
|
||||
|
||||
/**
|
||||
* Create an adapter for the given items.
|
||||
*/
|
||||
@@ -315,16 +315,16 @@ public class ActivityPicker extends AlertActivity implements
|
||||
if (convertView == null) {
|
||||
convertView = mInflater.inflate(R.layout.pick_item, parent, false);
|
||||
}
|
||||
|
||||
|
||||
Item item = (Item) getItem(position);
|
||||
TextView textView = (TextView) convertView;
|
||||
textView.setText(item.label);
|
||||
textView.setCompoundDrawablesWithIntrinsicBounds(item.icon, null, null, null);
|
||||
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility class to resize icons to match default icon size. Code is mostly
|
||||
* borrowed from Launcher.
|
||||
@@ -336,14 +336,14 @@ public class ActivityPicker extends AlertActivity implements
|
||||
private final DisplayMetrics mMetrics;
|
||||
private final Rect mOldBounds = new Rect();
|
||||
private final Canvas mCanvas = new Canvas();
|
||||
|
||||
|
||||
public IconResizer(int width, int height, DisplayMetrics metrics) {
|
||||
mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
|
||||
Paint.FILTER_BITMAP_FLAG));
|
||||
|
||||
mMetrics = metrics;
|
||||
mIconWidth = width;
|
||||
mIconHeight = height;
|
||||
mIconHeight = height;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,7 +356,7 @@ public class ActivityPicker extends AlertActivity implements
|
||||
* @param icon The icon to get a thumbnail of.
|
||||
*
|
||||
* @return A thumbnail for the specified icon or the icon itself if the
|
||||
* thumbnail could not be created.
|
||||
* thumbnail could not be created.
|
||||
*/
|
||||
public Drawable createIconThumbnail(Drawable icon) {
|
||||
int width = mIconWidth;
|
||||
@@ -365,7 +365,7 @@ public class ActivityPicker extends AlertActivity implements
|
||||
if (icon == null) {
|
||||
return new EmptyDrawable(width, height);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
if (icon instanceof PaintDrawable) {
|
||||
PaintDrawable painter = (PaintDrawable) icon;
|
||||
@@ -381,17 +381,17 @@ public class ActivityPicker extends AlertActivity implements
|
||||
}
|
||||
int iconWidth = icon.getIntrinsicWidth();
|
||||
int iconHeight = icon.getIntrinsicHeight();
|
||||
|
||||
|
||||
if (iconWidth > 0 && iconHeight > 0) {
|
||||
if (width < iconWidth || height < iconHeight) {
|
||||
final float ratio = (float) iconWidth / iconHeight;
|
||||
|
||||
|
||||
if (iconWidth > iconHeight) {
|
||||
height = (int) (width / ratio);
|
||||
} else if (iconHeight > iconWidth) {
|
||||
width = (int) (height * ratio);
|
||||
}
|
||||
|
||||
|
||||
final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
|
||||
Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
|
||||
final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
|
||||
@@ -429,7 +429,7 @@ public class ActivityPicker extends AlertActivity implements
|
||||
canvas.setBitmap(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (Throwable t) {
|
||||
icon = new EmptyDrawable(width, height);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ import android.content.Intent;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
public class DefaultRingtonePreference extends RingtonePreference {
|
||||
private static final String TAG = "DefaultRingtonePreference";
|
||||
@@ -43,6 +46,29 @@ public class DefaultRingtonePreference extends RingtonePreference {
|
||||
|
||||
@Override
|
||||
protected void onSaveRingtone(Uri ringtoneUri) {
|
||||
if (ringtoneUri == null) {
|
||||
setActualDefaultRingtoneUri(ringtoneUri);
|
||||
return;
|
||||
}
|
||||
|
||||
String mimeType = mUserContext.getContentResolver().getType(ringtoneUri);
|
||||
if (mimeType == null) {
|
||||
Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri
|
||||
+ " ignored: failure to find mimeType (no access from this context?)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) {
|
||||
Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri
|
||||
+ " ignored: associated mimeType:" + mimeType + " is not an audio type");
|
||||
return;
|
||||
}
|
||||
|
||||
setActualDefaultRingtoneUri(ringtoneUri);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setActualDefaultRingtoneUri(Uri ringtoneUri) {
|
||||
RingtoneManager.setActualDefaultRingtoneUri(mUserContext, getRingtoneType(), ringtoneUri);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import java.util.Objects;
|
||||
|
||||
public class FallbackHome extends Activity {
|
||||
private static final String TAG = "FallbackHome";
|
||||
private static final int PROGRESS_TIMEOUT = 2000;
|
||||
private int mProgressTimeout;
|
||||
|
||||
private boolean mProvisioned;
|
||||
private WallpaperManager mWallManager;
|
||||
@@ -76,6 +76,12 @@ public class FallbackHome extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mProgressTimeout = getResources().getInteger(
|
||||
com.android.internal.R.integer.config_progressTimeoutFallbackHome);
|
||||
|
||||
if (mProgressTimeout <= 0) {
|
||||
mProgressTimeout = 0;
|
||||
}
|
||||
|
||||
// Set ourselves totally black before the device is provisioned so that
|
||||
// we don't flash the wallpaper before SUW
|
||||
@@ -107,7 +113,7 @@ public class FallbackHome extends Activity {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (mProvisioned) {
|
||||
mHandler.postDelayed(mProgressTimeoutRunnable, PROGRESS_TIMEOUT);
|
||||
mHandler.postDelayed(mProgressTimeoutRunnable, mProgressTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
|
||||
|
||||
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
|
||||
import android.accounts.Account;
|
||||
@@ -23,6 +26,7 @@ import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorDescription;
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
@@ -490,9 +494,20 @@ public class MainClear extends InstrumentedFragment implements OnGlobalLayoutLis
|
||||
|
||||
if (profilesSize > 1) {
|
||||
View titleView = Utils.inflateCategoryHeader(inflater, contents);
|
||||
titleView.setPadding(0 /* left */, titleView.getPaddingTop(),
|
||||
0 /* right */, titleView.getPaddingBottom());
|
||||
final TextView titleText = (TextView) titleView.findViewById(android.R.id.title);
|
||||
titleText.setText(userInfo.isManagedProfile() ? R.string.category_work
|
||||
: R.string.category_personal);
|
||||
|
||||
DevicePolicyManager devicePolicyManager =
|
||||
context.getSystemService(DevicePolicyManager.class);
|
||||
|
||||
if (userInfo.isManagedProfile()) {
|
||||
titleText.setText(devicePolicyManager.getResources().getString(
|
||||
WORK_CATEGORY_HEADER, () -> getString(R.string.category_work)));
|
||||
} else {
|
||||
titleText.setText(devicePolicyManager.getResources().getString(
|
||||
PERSONAL_CATEGORY_HEADER, () -> getString(R.string.category_personal)));
|
||||
}
|
||||
contents.addView(titleView);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.oemlock.OemLockManager;
|
||||
@@ -67,6 +68,8 @@ import com.google.android.setupdesign.GlifLayout;
|
||||
public class MainClearConfirm extends InstrumentedFragment {
|
||||
private static final String TAG = "MainClearConfirm";
|
||||
|
||||
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
|
||||
|
||||
@VisibleForTesting View mContentView;
|
||||
private boolean mEraseSdCard;
|
||||
@VisibleForTesting boolean mEraseEsims;
|
||||
@@ -83,6 +86,11 @@ public class MainClearConfirm extends InstrumentedFragment {
|
||||
return;
|
||||
}
|
||||
|
||||
// pre-flight check hardware support PersistentDataBlockManager
|
||||
if (SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("")) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PersistentDataBlockManager pdbManager = (PersistentDataBlockManager)
|
||||
getActivity().getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
|
||||
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.content.Intent;
|
||||
import android.icu.text.MessageFormat;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
@@ -30,6 +34,10 @@ import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Activity that shows a dialog explaining that a CA cert is allowing someone to monitor network
|
||||
* traffic. This activity should be launched for the user into which the CA cert is installed
|
||||
@@ -71,12 +79,30 @@ public class MonitoringCertInfoActivity extends Activity implements OnClickListe
|
||||
builder.setOnDismissListener(this);
|
||||
|
||||
if (dpm.getProfileOwnerAsUser(mUserId) != null) {
|
||||
builder.setMessage(getResources().getQuantityString(R.plurals.ssl_ca_cert_info_message,
|
||||
numberOfCertificates, dpm.getProfileOwnerNameAsUser(mUserId)));
|
||||
MessageFormat msgFormat = new MessageFormat(
|
||||
dpm.getResources().getString(
|
||||
WORK_PROFILE_INSTALLED_CERTIFICATE_AUTHORITY_WARNING,
|
||||
() -> getString(R.string.ssl_ca_cert_info_message)),
|
||||
Locale.getDefault());
|
||||
|
||||
Map<String, Object> arguments = new HashMap<>();
|
||||
arguments.put("numberOfCertificates", numberOfCertificates);
|
||||
arguments.put("orgName", dpm.getProfileOwnerNameAsUser(mUserId));
|
||||
|
||||
builder.setMessage(msgFormat.format(arguments));
|
||||
} else if (dpm.getDeviceOwnerComponentOnCallingUser() != null) {
|
||||
builder.setMessage(getResources().getQuantityString(
|
||||
R.plurals.ssl_ca_cert_info_message_device_owner, numberOfCertificates,
|
||||
dpm.getDeviceOwnerNameOnAnyUser()));
|
||||
MessageFormat msgFormat = new MessageFormat(
|
||||
dpm.getResources()
|
||||
.getString(DEVICE_OWNER_INSTALLED_CERTIFICATE_AUTHORITY_WARNING,
|
||||
() -> getResources().getString(
|
||||
R.string.ssl_ca_cert_info_message_device_owner)),
|
||||
Locale.getDefault());
|
||||
|
||||
Map<String, Object> arguments = new HashMap<>();
|
||||
arguments.put("numberOfCertificates", numberOfCertificates);
|
||||
arguments.put("orgName", dpm.getDeviceOwnerNameOnAnyUser());
|
||||
|
||||
builder.setMessage(msgFormat.format(arguments));
|
||||
} else {
|
||||
// Consumer case. Show scary warning.
|
||||
builder.setIcon(android.R.drawable.stat_notify_error);
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.settings;
|
||||
|
||||
import static android.view.HapticFeedbackConstants.CLOCK_TICK;
|
||||
|
||||
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SETTINGS_SLIDER;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
@@ -30,9 +32,12 @@ import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import com.android.internal.jank.InteractionJankMonitor;
|
||||
|
||||
public class PointerSpeedPreference extends SeekBarDialogPreference implements
|
||||
SeekBar.OnSeekBarChangeListener {
|
||||
private final InputManager mIm;
|
||||
private final InteractionJankMonitor mJankMonitor = InteractionJankMonitor.getInstance();
|
||||
private SeekBar mSeekBar;
|
||||
|
||||
private int mOldSpeed;
|
||||
@@ -88,11 +93,15 @@ public class PointerSpeedPreference extends SeekBarDialogPreference implements
|
||||
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
mTouchInProgress = true;
|
||||
mJankMonitor.begin(InteractionJankMonitor.Configuration.Builder
|
||||
.withView(CUJ_SETTINGS_SLIDER, seekBar)
|
||||
.setTag(getKey()));
|
||||
}
|
||||
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
mTouchInProgress = false;
|
||||
mIm.tryPointerSpeed(seekBar.getProgress() + InputManager.MIN_POINTER_SPEED);
|
||||
mJankMonitor.end(CUJ_SETTINGS_SLIDER);
|
||||
}
|
||||
|
||||
private void onSpeedChanged() {
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
*/
|
||||
package com.android.settings;
|
||||
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_DIALOG_TITLE;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.SHARING_REMOTE_BUGREPORT_MESSAGE;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
@@ -42,12 +47,16 @@ public class RemoteBugreportActivity extends Activity {
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
|
||||
|
||||
final int notificationType = getIntent().getIntExtra(
|
||||
DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, -1);
|
||||
|
||||
if (notificationType == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.sharing_remote_bugreport_dialog_message)
|
||||
.setMessage(devicePolicyManager.getResources().getString(
|
||||
SHARING_REMOTE_BUGREPORT_MESSAGE,
|
||||
() -> getString(R.string.sharing_remote_bugreport_dialog_message)))
|
||||
.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
@@ -65,12 +74,22 @@ public class RemoteBugreportActivity extends Activity {
|
||||
} else if (notificationType == DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED
|
||||
|| notificationType
|
||||
== DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
|
||||
|
||||
int defaultMessageId = notificationType
|
||||
== DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED
|
||||
? R.string.share_remote_bugreport_dialog_message
|
||||
: R.string.share_remote_bugreport_dialog_message_finished;
|
||||
String overrideMessageId = notificationType
|
||||
== DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED
|
||||
? SHARE_REMOTE_BUGREPORT_NOT_FINISHED_REQUEST_CONSENT
|
||||
: SHARE_REMOTE_BUGREPORT_FINISHED_REQUEST_CONSENT;
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.share_remote_bugreport_dialog_title)
|
||||
.setMessage(notificationType
|
||||
== DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED
|
||||
? R.string.share_remote_bugreport_dialog_message
|
||||
: R.string.share_remote_bugreport_dialog_message_finished)
|
||||
.setTitle(devicePolicyManager.getResources().getString(
|
||||
SHARE_REMOTE_BUGREPORT_DIALOG_TITLE,
|
||||
() -> getString(R.string.share_remote_bugreport_dialog_title)))
|
||||
.setMessage(devicePolicyManager.getResources().getString(overrideMessageId,
|
||||
() -> getString(defaultMessageId)))
|
||||
.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
|
||||
@@ -201,7 +201,8 @@ public class ResetNetwork extends InstrumentedFragment {
|
||||
name = record.getNumber();
|
||||
}
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
name = record.getCarrierName().toString();
|
||||
CharSequence carrierName = record.getCarrierName();
|
||||
name = TextUtils.isEmpty(carrierName) ? "" : carrierName.toString();
|
||||
}
|
||||
if (TextUtils.isEmpty(name)) {
|
||||
name = String.format("MCC:%s MNC:%s Slot:%s Id:%s", record.getMcc(),
|
||||
|
||||
@@ -30,7 +30,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
@@ -53,7 +52,6 @@ public class RestrictedListPreference extends CustomListPreference {
|
||||
|
||||
public RestrictedListPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setWidgetLayoutResource(R.layout.restricted_icon);
|
||||
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
|
||||
}
|
||||
|
||||
@@ -67,10 +65,6 @@ public class RestrictedListPreference extends CustomListPreference {
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
mHelper.onBindViewHolder(holder);
|
||||
final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
|
||||
if (restrictedIcon != null) {
|
||||
restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,11 +181,9 @@ public class RestrictedListPreference extends CustomListPreference {
|
||||
View root = super.getView(position, convertView, parent);
|
||||
CharSequence entry = getItem(position);
|
||||
CheckedTextView text = (CheckedTextView) root.findViewById(R.id.text1);
|
||||
ImageView padlock = (ImageView) root.findViewById(R.id.restricted_lock_icon);
|
||||
if (isRestrictedForEntry(entry)) {
|
||||
text.setEnabled(false);
|
||||
text.setChecked(false);
|
||||
padlock.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if (mSelectedIndex != -1) {
|
||||
text.setChecked(position == mSelectedIndex);
|
||||
@@ -199,7 +191,6 @@ public class RestrictedListPreference extends CustomListPreference {
|
||||
if (!text.isEnabled()) {
|
||||
text.setEnabled(true);
|
||||
}
|
||||
padlock.setVisibility(View.GONE);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -16,16 +16,24 @@
|
||||
|
||||
package com.android.settings;
|
||||
|
||||
import static android.provider.Settings.ACTION_PRIVACY_SETTINGS;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.ims.ImsRcsManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.biometrics.face.FaceSettings;
|
||||
import com.android.settings.core.FeatureFlags;
|
||||
import com.android.settings.enterprise.EnterprisePrivacySettings;
|
||||
import com.android.settings.network.MobileNetworkIntentConverter;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
|
||||
import com.android.settings.security.SecuritySettingsFeatureProvider;
|
||||
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
@@ -42,6 +50,8 @@ public class Settings extends SettingsActivity {
|
||||
public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class CreateShortcutActivity extends SettingsActivity { /* empty */ }
|
||||
public static class FaceSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/** Container for {@link FaceSettings} to use with a pre-defined task affinity. */
|
||||
public static class FaceSettingsInternalActivity extends SettingsActivity { /* empty */ }
|
||||
public static class FingerprintSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class CombinedBiometricSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class CombinedBiometricProfileSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
@@ -131,6 +141,27 @@ public class Settings extends SettingsActivity {
|
||||
/** Activity for the security dashboard. */
|
||||
public static class SecurityDashboardActivity extends SettingsActivity {
|
||||
|
||||
private static final String TAG = "SecurityDashboardActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
handleSafetyCenterRedirection();
|
||||
}
|
||||
|
||||
/** Redirects to SafetyCenter if enabled. */
|
||||
@VisibleForTesting
|
||||
public void handleSafetyCenterRedirection() {
|
||||
if (SafetyCenterManagerWrapper.get().isEnabled(this)) {
|
||||
try {
|
||||
startActivity(new Intent(Intent.ACTION_SAFETY_CENTER));
|
||||
finish();
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "Unable to open safety center", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether the given fragment is allowed. */
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
@@ -161,12 +192,39 @@ public class Settings extends SettingsActivity {
|
||||
return alternativeFragmentClassname;
|
||||
}
|
||||
}
|
||||
/** Activity for the Advanced security settings. */
|
||||
public static class SecurityAdvancedSettings extends SettingsActivity { /* empty */ }
|
||||
public static class UsageAccessSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AppUsageAccessSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class LocationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ScanningSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class WifiScanningSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PrivacyDashboardActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity for the privacy dashboard. */
|
||||
public static class PrivacyDashboardActivity extends SettingsActivity {
|
||||
|
||||
private static final String TAG = "PrivacyDashboardActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
handleSafetyCenterRedirection();
|
||||
}
|
||||
|
||||
/** Redirects to SafetyCenter if enabled. */
|
||||
@VisibleForTesting
|
||||
public void handleSafetyCenterRedirection() {
|
||||
if (ACTION_PRIVACY_SETTINGS.equals(getIntent().getAction())
|
||||
&& SafetyCenterManagerWrapper.get().isEnabled(this)) {
|
||||
try {
|
||||
startActivity(new Intent(Intent.ACTION_SAFETY_CENTER));
|
||||
finish();
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "Unable to open safety center", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static class PrivacyControlsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PrivacySettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class FactoryResetActivity extends SettingsActivity {
|
||||
@Override
|
||||
@@ -215,6 +273,7 @@ public class Settings extends SettingsActivity {
|
||||
public static class VrListenersSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PremiumSmsAccessActivity extends SettingsActivity { /* empty */ }
|
||||
public static class PictureInPictureSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class TurnScreenOnSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AppPictureInPictureSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ZenAccessSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ZenAccessDetailSettingsActivity extends SettingsActivity {}
|
||||
@@ -237,6 +296,7 @@ public class Settings extends SettingsActivity {
|
||||
public static class AppBubbleNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NotificationAssistantSettingsActivity extends SettingsActivity{ /* empty */ }
|
||||
public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NotificationReviewPermissionsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ChannelNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ChannelGroupNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
@@ -244,6 +304,8 @@ public class Settings extends SettingsActivity {
|
||||
public static class AutomaticStorageManagerSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class GamesStorageActivity extends SettingsActivity { /* empty */ }
|
||||
public static class GestureNavigationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity to manage 2-/3-button navigation configuration. */
|
||||
public static class ButtonNavigationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class InteractAcrossProfilesSettingsActivity extends SettingsActivity {
|
||||
/* empty */
|
||||
}
|
||||
@@ -303,6 +365,48 @@ public class Settings extends SettingsActivity {
|
||||
public static class WifiCallingDisclaimerActivity extends SettingsActivity { /* empty */ }
|
||||
public static class MobileNetworkListActivity extends SettingsActivity {}
|
||||
public static class PowerMenuSettingsActivity extends SettingsActivity {}
|
||||
public static class MobileNetworkActivity extends SettingsActivity {
|
||||
|
||||
public static final String TAG = "MobileNetworkActivity";
|
||||
public static final String EXTRA_MMS_MESSAGE = "mms_message";
|
||||
public static final String EXTRA_SHOW_CAPABILITY_DISCOVERY_OPT_IN =
|
||||
"show_capability_discovery_opt_in";
|
||||
|
||||
private MobileNetworkIntentConverter mIntentConverter;
|
||||
|
||||
/**
|
||||
* Override of #onNewIntent() requires Activity to have "singleTop" launch mode within
|
||||
* AndroidManifest.xml
|
||||
*/
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
Log.d(TAG, "Starting onNewIntent");
|
||||
|
||||
createUiFromIntent(null /* savedState */, convertIntent(intent));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
return convertIntent(super.getIntent());
|
||||
}
|
||||
|
||||
private Intent convertIntent(Intent copyFrom) {
|
||||
if (mIntentConverter == null) {
|
||||
mIntentConverter = new MobileNetworkIntentConverter(this);
|
||||
}
|
||||
Intent intent = mIntentConverter.apply(copyFrom);
|
||||
return (intent == null) ? copyFrom : intent;
|
||||
}
|
||||
|
||||
public static boolean doesIntentContainOptInAction(Intent intent) {
|
||||
String intentAction = (intent != null ? intent.getAction() : null);
|
||||
return TextUtils.equals(intentAction,
|
||||
ImsRcsManager.ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity for BugReportHandlerPicker.
|
||||
*/
|
||||
@@ -327,4 +431,9 @@ public class Settings extends SettingsActivity {
|
||||
public static class AppDashboardActivity extends SettingsActivity {}
|
||||
|
||||
public static class AdaptiveBrightnessActivity extends SettingsActivity { /* empty */ }
|
||||
|
||||
/**
|
||||
* Activity for OneHandedSettings
|
||||
*/
|
||||
public static class OneHandedSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import static com.android.settings.applications.appinfo.AppButtonsPreferenceCont
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -33,6 +34,7 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.graphics.drawable.Icon;
|
||||
@@ -64,8 +66,8 @@ import com.android.settings.core.SettingsBaseActivity;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.core.gateway.SettingsGateway;
|
||||
import com.android.settings.dashboard.DashboardFeatureProvider;
|
||||
import com.android.settings.homepage.DeepLinkHomepageActivityInternal;
|
||||
import com.android.settings.homepage.SettingsHomepageActivity;
|
||||
import com.android.settings.homepage.SliceDeepLinkHomepageActivity;
|
||||
import com.android.settings.homepage.TopLevelSettings;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.wfd.WifiDisplaySettings;
|
||||
@@ -143,6 +145,7 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
|
||||
public static final String EXTRA_SHOW_FRAGMENT_AS_SUBSETTING =
|
||||
":settings:show_fragment_as_subsetting";
|
||||
public static final String EXTRA_IS_SECOND_LAYER_PAGE = ":settings:is_second_layer_page";
|
||||
|
||||
/**
|
||||
* Additional extra of Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK.
|
||||
@@ -150,6 +153,8 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
*/
|
||||
public static final String EXTRA_IS_FROM_SLICE = "is_from_slice";
|
||||
|
||||
public static final String EXTRA_USER_HANDLE = "user_handle";
|
||||
|
||||
/**
|
||||
* Personal or Work profile tab of {@link ProfileSelectFragment}
|
||||
* <p>0: Personal tab.
|
||||
@@ -251,16 +256,18 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
getMetaData();
|
||||
final Intent intent = getIntent();
|
||||
|
||||
if (shouldShowTwoPaneDeepLink(intent)) {
|
||||
launchHomepageForTwoPaneDeepLink(intent);
|
||||
finishAndRemoveTask();
|
||||
if (shouldShowTwoPaneDeepLink(intent) && tryStartTwoPaneDeepLink(intent)) {
|
||||
finish();
|
||||
super.onCreate(savedState);
|
||||
return;
|
||||
}
|
||||
|
||||
super.onCreate(savedState);
|
||||
Log.d(LOG_TAG, "Starting onCreate");
|
||||
createUiFromIntent(savedState, intent);
|
||||
}
|
||||
|
||||
protected void createUiFromIntent(Bundle savedState, Intent intent) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
final FeatureFactory factory = FeatureFactory.getFactory(this);
|
||||
@@ -301,12 +308,12 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
launchSettingFragment(initialFragmentName, intent);
|
||||
}
|
||||
|
||||
final boolean isInSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
final boolean isActionBarButtonEnabled = isActionBarButtonEnabled(intent);
|
||||
|
||||
final ActionBar actionBar = getActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(!isInSetupWizard);
|
||||
actionBar.setHomeButtonEnabled(!isInSetupWizard);
|
||||
actionBar.setDisplayHomeAsUpEnabled(isActionBarButtonEnabled);
|
||||
actionBar.setHomeButtonEnabled(isActionBarButtonEnabled);
|
||||
actionBar.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
mMainSwitch = findViewById(R.id.switch_bar);
|
||||
@@ -366,6 +373,18 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isActionBarButtonEnabled(Intent intent) {
|
||||
if (WizardManagerHelper.isAnySetupWizard(intent)) {
|
||||
return false;
|
||||
}
|
||||
final boolean isSecondLayerPage =
|
||||
intent.getBooleanExtra(EXTRA_IS_SECOND_LAYER_PAGE, false);
|
||||
|
||||
// TODO: move Settings's ActivityEmbeddingUtils to SettingsLib.
|
||||
return !com.android.settingslib.activityembedding.ActivityEmbeddingUtils
|
||||
.shouldHideNavigateUpButton(this, isSecondLayerPage);
|
||||
}
|
||||
|
||||
private boolean isSubSettings(Intent intent) {
|
||||
return this instanceof SubSettings ||
|
||||
intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
|
||||
@@ -398,7 +417,7 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
return trampolineIntent;
|
||||
}
|
||||
|
||||
private void launchHomepageForTwoPaneDeepLink(Intent intent) {
|
||||
private boolean tryStartTwoPaneDeepLink(Intent intent) {
|
||||
final Intent trampolineIntent;
|
||||
if (intent.getBooleanExtra(EXTRA_IS_FROM_SLICE, false)) {
|
||||
// Get menu key for slice deep link case.
|
||||
@@ -408,11 +427,26 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
mHighlightMenuKey = highlightMenuKey;
|
||||
}
|
||||
trampolineIntent = getTrampolineIntent(intent, mHighlightMenuKey);
|
||||
trampolineIntent.setClass(this, SliceDeepLinkHomepageActivity.class);
|
||||
trampolineIntent.setClass(this, DeepLinkHomepageActivityInternal.class);
|
||||
} else {
|
||||
trampolineIntent = getTrampolineIntent(intent, mHighlightMenuKey);
|
||||
}
|
||||
startActivity(trampolineIntent);
|
||||
|
||||
try {
|
||||
final UserManager um = getSystemService(UserManager.class);
|
||||
final UserInfo userInfo = um.getUserInfo(getUser().getIdentifier());
|
||||
if (userInfo.isManagedProfile()) {
|
||||
trampolineIntent.setClass(this, DeepLinkHomepageActivityInternal.class)
|
||||
.putExtra(EXTRA_USER_HANDLE, getUser());
|
||||
startActivityAsUser(trampolineIntent, um.getPrimaryUser().getUserHandle());
|
||||
} else {
|
||||
startActivity(trampolineIntent);
|
||||
}
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Deep link homepage is not available to show 2-pane UI");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean shouldShowTwoPaneDeepLink(Intent intent) {
|
||||
@@ -420,8 +454,11 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the activity is not the task root, it should not start trampoline for deep links.
|
||||
if (!isTaskRoot()) {
|
||||
// If the activity is task root, starting trampoline is needed in order to show two-pane UI.
|
||||
// If FLAG_ACTIVITY_NEW_TASK is set, the activity will become the start of a new task on
|
||||
// this history stack, so starting trampoline is needed in order to notify the homepage that
|
||||
// the highlight key is changed.
|
||||
if (!isTaskRoot() && (intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -432,6 +469,15 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the activity's launch mode is "singleInstance", it can't be embedded in Settings since
|
||||
// it will be created in a new task.
|
||||
ActivityInfo info = intent.resolveActivityInfo(getPackageManager(),
|
||||
PackageManager.MATCH_DEFAULT_ONLY);
|
||||
if (info.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
|
||||
Log.w(LOG_TAG, "launchMode: singleInstance");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_IS_FROM_SLICE, false)) {
|
||||
// Slice deep link starts the Intent using SubSettingLauncher. Returns true to show
|
||||
// 2-pane deep link.
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.app.Application;
|
||||
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
|
||||
import com.android.settings.homepage.SettingsHomepageActivity;
|
||||
import com.android.settingslib.applications.AppIconCacheManager;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@@ -44,4 +45,10 @@ public class SettingsApplication extends Application {
|
||||
public SettingsHomepageActivity getHomeActivity() {
|
||||
return mHomeActivity.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
AppIconCacheManager.getInstance().release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -54,6 +55,7 @@ import com.android.settingslib.search.Indexable;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -63,12 +65,13 @@ import java.util.UUID;
|
||||
public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment
|
||||
implements DialogCreatable, HelpResourceProvider, Indexable {
|
||||
|
||||
private static final String TAG = "SettingsPreference";
|
||||
private static final String TAG = "SettingsPreferenceFragment";
|
||||
|
||||
private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
|
||||
|
||||
private static final int ORDER_FIRST = -1;
|
||||
|
||||
protected DevicePolicyManager mDevicePolicyManager;
|
||||
private SettingsDialogFragment mDialogFragment;
|
||||
// Cache the content resolver for async callbacks
|
||||
private ContentResolver mContentResolver;
|
||||
@@ -121,10 +124,20 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
|
||||
public HighlightablePreferenceGroupAdapter mAdapter;
|
||||
private boolean mPreferenceHighlighted = false;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
if (shouldSkipForInitialSUW() && !WizardManagerHelper.isDeviceProvisioned(getContext())) {
|
||||
Log.w(TAG, "Skip " + getClass().getSimpleName() + " before SUW completed.");
|
||||
finish();
|
||||
}
|
||||
super.onAttach(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
mDevicePolicyManager = getContext().getSystemService(DevicePolicyManager.class);
|
||||
if (icicle != null) {
|
||||
mPreferenceHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
|
||||
}
|
||||
@@ -267,6 +280,16 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
|
||||
|| (mAdapter.getPreferenceAdapterPosition(preference) != RecyclerView.NO_POSITION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether UI should be skipped in the initial SUW flow.
|
||||
*
|
||||
* @return {@code true} when UI should be skipped in the initial SUW flow.
|
||||
* {@code false} when UI should not be skipped in the initial SUW flow.
|
||||
*/
|
||||
protected boolean shouldSkipForInitialSUW() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void onDataSetChanged() {
|
||||
highlightPreferenceIfNeeded();
|
||||
updateEmptyView();
|
||||
@@ -708,4 +731,35 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
|
||||
final Activity activity = getActivity();
|
||||
return activity == null || activity.isFinishing() || activity.isDestroyed();
|
||||
}
|
||||
|
||||
protected void replaceEnterprisePreferenceScreenTitle(String overrideKey, int resource) {
|
||||
getActivity().setTitle(mDevicePolicyManager.getResources().getString(
|
||||
overrideKey, () -> getString(resource)));
|
||||
}
|
||||
|
||||
protected void replaceEnterpriseStringSummary(
|
||||
String preferenceKey, String overrideKey, int resource) {
|
||||
Preference preference = findPreference(preferenceKey);
|
||||
if (preference == null) {
|
||||
Log.d(TAG, "Could not find enterprise preference " + preferenceKey);
|
||||
return;
|
||||
}
|
||||
|
||||
preference.setSummary(
|
||||
mDevicePolicyManager.getResources().getString(overrideKey,
|
||||
() -> getString(resource)));
|
||||
}
|
||||
|
||||
protected void replaceEnterpriseStringTitle(
|
||||
String preferenceKey, String overrideKey, int resource) {
|
||||
Preference preference = findPreference(preferenceKey);
|
||||
if (preference == null) {
|
||||
Log.d(TAG, "Could not find enterprise preference " + preferenceKey);
|
||||
return;
|
||||
}
|
||||
|
||||
preference.setTitle(
|
||||
mDevicePolicyManager.getResources().getString(overrideKey,
|
||||
() -> getString(resource)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ public class SetupWizardUtils {
|
||||
if (WizardManagerHelper.isAnySetupWizard(intent)) {
|
||||
if (ThemeHelper.isSetupWizardDayNightEnabled(context)) {
|
||||
switch (theme) {
|
||||
case ThemeHelper.THEME_GLIF_V4_LIGHT:
|
||||
case ThemeHelper.THEME_GLIF_V4:
|
||||
return R.style.GlifV4Theme_DayNight;
|
||||
case ThemeHelper.THEME_GLIF_V3_LIGHT:
|
||||
case ThemeHelper.THEME_GLIF_V3:
|
||||
return R.style.GlifV3Theme_DayNight;
|
||||
@@ -60,6 +63,10 @@ public class SetupWizardUtils {
|
||||
}
|
||||
} else {
|
||||
switch (theme) {
|
||||
case ThemeHelper.THEME_GLIF_V4_LIGHT:
|
||||
return R.style.GlifV4Theme_Light;
|
||||
case ThemeHelper.THEME_GLIF_V4:
|
||||
return R.style.GlifV4Theme;
|
||||
case ThemeHelper.THEME_GLIF_V3_LIGHT:
|
||||
return R.style.GlifV3Theme_Light;
|
||||
case ThemeHelper.THEME_GLIF_V3:
|
||||
@@ -76,6 +83,9 @@ public class SetupWizardUtils {
|
||||
}
|
||||
} else {
|
||||
switch (theme) {
|
||||
case ThemeHelper.THEME_GLIF_V4_LIGHT:
|
||||
case ThemeHelper.THEME_GLIF_V4:
|
||||
return R.style.GlifV4Theme;
|
||||
case ThemeHelper.THEME_GLIF_V3_LIGHT:
|
||||
case ThemeHelper.THEME_GLIF_V3:
|
||||
return R.style.GlifV3Theme;
|
||||
|
||||
@@ -416,8 +416,11 @@ public class TetherSettings extends RestrictedSettingsFragment
|
||||
if (usbTethered) {
|
||||
mUsbTether.setEnabled(!mDataSaverEnabled);
|
||||
mUsbTether.setChecked(true);
|
||||
mUsbTether.setDisabledByAdmin(
|
||||
checkIfUsbDataSignalingIsDisabled(mContext, UserHandle.myUserId()));
|
||||
final RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
|
||||
checkIfUsbDataSignalingIsDisabled(mContext, UserHandle.myUserId());
|
||||
if (enforcedAdmin != null) {
|
||||
mUsbTether.setDisabledByAdmin(enforcedAdmin);
|
||||
}
|
||||
} else {
|
||||
mUsbTether.setChecked(false);
|
||||
updateUsbPreference();
|
||||
|
||||
@@ -34,7 +34,7 @@ import android.widget.Spinner;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.TrustedCredentialsSettings.CertHolder;
|
||||
import com.android.settings.TrustedCredentialsFragment.CertHolder;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
1030
src/com/android/settings/TrustedCredentialsFragment.java
Normal file
1030
src/com/android/settings/TrustedCredentialsFragment.java
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,6 @@ import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.style.TtsSpan;
|
||||
import android.util.ArraySet;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -419,7 +418,7 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
public static UserHandle getManagedProfile(UserManager userManager) {
|
||||
final List<UserHandle> userProfiles = userManager.getUserProfiles();
|
||||
for (UserHandle profile : userProfiles) {
|
||||
if (profile.getIdentifier() == userManager.getUserHandle()) {
|
||||
if (profile.getIdentifier() == userManager.getProcessUserId()) {
|
||||
continue;
|
||||
}
|
||||
final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier());
|
||||
@@ -1220,7 +1219,7 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getHomepageIconColor(Context context) {
|
||||
return getColorAttrDefaultColor(context, android.R.attr.textColorSecondary);
|
||||
return getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1228,6 +1227,6 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getHomepageIconColorHighlight(Context context) {
|
||||
return getColorAttrDefaultColor(context, android.R.attr.textColorSecondaryInverse);
|
||||
return context.getColor(R.color.accent_select_primary_text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class AccessibilityButtonFooterPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLearnMoreContentDescription() {
|
||||
protected String getLearnMoreText() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_button_gesture_footer_learn_more_content_description);
|
||||
}
|
||||
@@ -50,9 +50,10 @@ public class AccessibilityButtonFooterPreferenceController extends
|
||||
final int titleResource = AccessibilityUtil.isGestureNavigateEnabled(mContext)
|
||||
? R.string.accessibility_button_gesture_description
|
||||
: R.string.accessibility_button_description;
|
||||
final CharSequence footerText = mContext.getText(titleResource);
|
||||
final AccessibilityFooterPreference footerPreference =
|
||||
screen.findPreference(getPreferenceKey());
|
||||
footerPreference.setTitle(titleResource);
|
||||
footerPreference.setTitle(footerText);
|
||||
super.displayPreference(screen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class AccessibilityControlTimeoutFooterPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLearnMoreContentDescription() {
|
||||
protected String getLearnMoreText() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_control_timeout_footer_learn_more_content_description);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.app.Activity;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
@@ -49,6 +50,7 @@ import java.util.Set;
|
||||
public class AccessibilityDetailsSettingsFragment extends InstrumentedFragment {
|
||||
|
||||
private final static String TAG = "A11yDetailsSettings";
|
||||
private AppOpsManager mAppOps;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -59,6 +61,8 @@ public class AccessibilityDetailsSettingsFragment extends InstrumentedFragment {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mAppOps = getActivity().getSystemService(AppOpsManager.class);
|
||||
|
||||
// In case the Intent doesn't have component name, go to a11y services list.
|
||||
final String extraComponentName = getActivity().getIntent().getStringExtra(
|
||||
Intent.EXTRA_COMPONENT_NAME);
|
||||
@@ -127,10 +131,11 @@ public class AccessibilityDetailsSettingsFragment extends InstrumentedFragment {
|
||||
}
|
||||
|
||||
// In case this accessibility service isn't permitted, go to a11y services list.
|
||||
if (!isServiceAllowed(componentName.getPackageName())) {
|
||||
if (!isServiceAllowed(info.getResolveInfo().serviceInfo.applicationInfo.uid,
|
||||
componentName.getPackageName())) {
|
||||
Log.w(TAG,
|
||||
"openAccessibilityDetailsSettingsAndFinish: target accessibility service is"
|
||||
+ "prohibited by Device Admin.");
|
||||
+ "prohibited by Device Admin or App Op.");
|
||||
return false;
|
||||
}
|
||||
openSubSettings(ToggleAccessibilityServicePreferenceFragment.class.getName(),
|
||||
@@ -148,11 +153,23 @@ public class AccessibilityDetailsSettingsFragment extends InstrumentedFragment {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isServiceAllowed(String packageName) {
|
||||
boolean isServiceAllowed(int uid, String packageName) {
|
||||
final DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class);
|
||||
final List<String> permittedServices = dpm.getPermittedAccessibilityServices(
|
||||
UserHandle.myUserId());
|
||||
return (permittedServices == null || permittedServices.contains(packageName));
|
||||
if (permittedServices != null && !permittedServices.contains(packageName)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
final int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
|
||||
uid, packageName);
|
||||
final boolean ecmEnabled = getContext().getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
|
||||
return !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
|
||||
} catch (Exception e) {
|
||||
// Fallback in case if app ops is not available in testing.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private AccessibilityServiceInfo getAccessibilityServiceInfo(ComponentName componentName) {
|
||||
@@ -206,11 +223,26 @@ public class AccessibilityDetailsSettingsFragment extends InstrumentedFragment {
|
||||
extras.putString(AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME,
|
||||
new ComponentName(packageName, settingsClassName).flattenToString());
|
||||
}
|
||||
|
||||
final String tileServiceClassName = info.getTileServiceName();
|
||||
if (!TextUtils.isEmpty(tileServiceClassName)) {
|
||||
extras.putString(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME,
|
||||
new ComponentName(packageName, tileServiceClassName).flattenToString());
|
||||
}
|
||||
|
||||
extras.putParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME, componentName);
|
||||
extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, info.getAnimatedImageRes());
|
||||
|
||||
final String htmlDescription = info.loadHtmlDescription(getActivity().getPackageManager());
|
||||
extras.putString(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, htmlDescription);
|
||||
|
||||
final CharSequence intro = info.loadIntro(getActivity().getPackageManager());
|
||||
extras.putCharSequence(AccessibilitySettings.EXTRA_INTRO, intro);
|
||||
|
||||
// We will log nonA11yTool status from PolicyWarningUIController; others none.
|
||||
extras.putLong(AccessibilitySettings.EXTRA_TIME_FOR_LOGGING,
|
||||
getActivity().getIntent().getLongExtra(
|
||||
AccessibilitySettings.EXTRA_TIME_FOR_LOGGING, 0));
|
||||
return extras;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -119,6 +118,11 @@ public class AccessibilityDialogUtils {
|
||||
* launch tutorial.
|
||||
*/
|
||||
int LAUNCH_ACCESSIBILITY_TUTORIAL = 1008;
|
||||
|
||||
/**
|
||||
* OPEN: Settings > Accessibility > Display size and text > Click 'Reset settings' button.
|
||||
*/
|
||||
int DIALOG_RESET_SETTINGS = 1009;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +135,6 @@ public class AccessibilityDialogUtils {
|
||||
DialogType.EDIT_SHORTCUT_GENERIC_SUW,
|
||||
DialogType.EDIT_SHORTCUT_MAGNIFICATION,
|
||||
DialogType.EDIT_SHORTCUT_MAGNIFICATION_SUW,
|
||||
DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT,
|
||||
})
|
||||
|
||||
public @interface DialogType {
|
||||
@@ -139,7 +142,6 @@ public class AccessibilityDialogUtils {
|
||||
int EDIT_SHORTCUT_GENERIC_SUW = 1;
|
||||
int EDIT_SHORTCUT_MAGNIFICATION = 2;
|
||||
int EDIT_SHORTCUT_MAGNIFICATION_SUW = 3;
|
||||
int EDIT_MAGNIFICATION_SWITCH_SHORTCUT = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,27 +161,6 @@ public class AccessibilityDialogUtils {
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to show the magnification edit shortcut dialog in Magnification.
|
||||
*
|
||||
* @param context A valid context
|
||||
* @param positiveBtnListener The positive button listener
|
||||
* @return A magnification edit shortcut dialog in Magnification
|
||||
*/
|
||||
public static Dialog createMagnificationSwitchShortcutDialog(Context context,
|
||||
CustomButtonsClickListener positiveBtnListener) {
|
||||
final View contentView = createSwitchShortcutDialogContentView(context);
|
||||
final AlertDialog alertDialog = new AlertDialog.Builder(context)
|
||||
.setView(contentView)
|
||||
.setTitle(context.getString(
|
||||
R.string.accessibility_magnification_switch_shortcut_title))
|
||||
.create();
|
||||
setCustomButtonsClickListener(alertDialog, contentView,
|
||||
positiveBtnListener, /* negativeBtnListener= */ null);
|
||||
setScrollIndicators(contentView);
|
||||
return alertDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the software shortcut in edit shortcut dialog.
|
||||
*
|
||||
@@ -233,56 +214,6 @@ public class AccessibilityDialogUtils {
|
||||
View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
|
||||
}
|
||||
|
||||
|
||||
interface CustomButtonsClickListener {
|
||||
void onClick(@CustomButton int which);
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation for customized dialog button type.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
CustomButton.POSITIVE,
|
||||
CustomButton.NEGATIVE,
|
||||
})
|
||||
|
||||
public @interface CustomButton {
|
||||
int POSITIVE = 1;
|
||||
int NEGATIVE = 2;
|
||||
}
|
||||
|
||||
private static void setCustomButtonsClickListener(Dialog dialog, View contentView,
|
||||
CustomButtonsClickListener positiveBtnListener,
|
||||
CustomButtonsClickListener negativeBtnListener) {
|
||||
final Button positiveButton = contentView.findViewById(
|
||||
R.id.custom_positive_button);
|
||||
final Button negativeButton = contentView.findViewById(
|
||||
R.id.custom_negative_button);
|
||||
|
||||
if (positiveButton != null) {
|
||||
positiveButton.setOnClickListener(v -> {
|
||||
if (positiveBtnListener != null) {
|
||||
positiveBtnListener.onClick(CustomButton.POSITIVE);
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
if (negativeButton != null) {
|
||||
negativeButton.setOnClickListener(v -> {
|
||||
if (negativeBtnListener != null) {
|
||||
negativeBtnListener.onClick(CustomButton.NEGATIVE);
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static View createSwitchShortcutDialogContentView(Context context) {
|
||||
return createEditDialogContentView(context, DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a content View for the edit shortcut dialog.
|
||||
*
|
||||
@@ -325,12 +256,6 @@ public class AccessibilityDialogUtils {
|
||||
initMagnifyShortcut(context, contentView);
|
||||
initAdvancedWidget(contentView);
|
||||
break;
|
||||
case DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT:
|
||||
contentView = inflater.inflate(
|
||||
R.layout.accessibility_edit_magnification_shortcut, null);
|
||||
final ImageView image = contentView.findViewById(R.id.image);
|
||||
image.setImageResource(retrieveSoftwareShortcutImageResId(context));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
@@ -548,18 +473,24 @@ public class AccessibilityDialogUtils {
|
||||
* @param context A valid context
|
||||
* @param dialogTitle The title of the dialog
|
||||
* @param customView The customized view
|
||||
* @param listener This listener will be invoked when the positive button in the dialog is
|
||||
* clicked
|
||||
* @param positiveButtonText The text of the positive button
|
||||
* @param positiveListener This listener will be invoked when the positive button in the dialog
|
||||
* is clicked
|
||||
* @param negativeButtonText The text of the negative button
|
||||
* @param negativeListener This listener will be invoked when the negative button in the dialog
|
||||
* is clicked
|
||||
* @return the {@link Dialog} with the given view
|
||||
*/
|
||||
public static Dialog createCustomDialog(Context context, CharSequence dialogTitle,
|
||||
View customView, DialogInterface.OnClickListener listener) {
|
||||
View customView, CharSequence positiveButtonText,
|
||||
DialogInterface.OnClickListener positiveListener, CharSequence negativeButtonText,
|
||||
DialogInterface.OnClickListener negativeListener) {
|
||||
final AlertDialog alertDialog = new AlertDialog.Builder(context)
|
||||
.setView(customView)
|
||||
.setTitle(dialogTitle)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.save, listener)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(positiveButtonText, positiveListener)
|
||||
.setNegativeButton(negativeButtonText, negativeListener)
|
||||
.create();
|
||||
if (customView instanceof ScrollView || customView instanceof AbsListView) {
|
||||
setScrollIndicators(customView);
|
||||
|
||||
@@ -25,9 +25,7 @@ import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
|
||||
/**
|
||||
* A custom preference acting as footer of a page. Disables the movement method by default.
|
||||
*/
|
||||
/** A custom preference acting as footer of a page. Disables the movement method by default. */
|
||||
public final class AccessibilityFooterPreference extends FooterPreference {
|
||||
|
||||
private boolean mLinkEnabled;
|
||||
@@ -46,12 +44,16 @@ public final class AccessibilityFooterPreference extends FooterPreference {
|
||||
|
||||
final TextView title = holder.itemView.findViewById(android.R.id.title);
|
||||
if (mLinkEnabled) {
|
||||
// When a TextView has a movement method, it will set the view to clickable. This makes
|
||||
// View.onTouchEvent always return true and consumes the touch event, essentially
|
||||
// nullifying any return values of MovementMethod.onTouchEvent.
|
||||
// When a TextView has a movement method, it will set the view to focusable and
|
||||
// clickable. This makes View.onTouchEvent always return true and consumes the touch
|
||||
// event, essentially nullifying any return values of MovementMethod.onTouchEvent.
|
||||
// To still allow propagating touch events to the parent when this view doesn't have
|
||||
// links, we only set the movement method here if the text contains links.
|
||||
title.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
// Groups of related title and link content by making the container focusable,
|
||||
// then make all the children inside not focusable.
|
||||
title.setFocusable(false);
|
||||
} else {
|
||||
title.setMovementMethod(/* movement= */ null);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.android.settingslib.HelpUtils;
|
||||
public class AccessibilityFooterPreferenceController extends BasePreferenceController {
|
||||
|
||||
private int mHelpResource;
|
||||
private String mLearnMoreContentDescription;
|
||||
private String mLearnMoreText;
|
||||
private String mIntroductionTitle;
|
||||
|
||||
public AccessibilityFooterPreferenceController(Context context, String key) {
|
||||
@@ -56,9 +56,9 @@ public class AccessibilityFooterPreferenceController extends BasePreferenceContr
|
||||
* Setups a help item in the {@link AccessibilityFooterPreference} with specific content
|
||||
* description.
|
||||
*/
|
||||
public void setupHelpLink(int helpResource, String learnMoreContentDescription) {
|
||||
public void setupHelpLink(int helpResource, String learnMoreText) {
|
||||
mHelpResource = helpResource;
|
||||
mLearnMoreContentDescription = learnMoreContentDescription;
|
||||
mLearnMoreText = learnMoreText;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,12 +73,12 @@ public class AccessibilityFooterPreferenceController extends BasePreferenceContr
|
||||
|
||||
/**
|
||||
* Overrides this if showing a help item in the {@link AccessibilityFooterPreference} with
|
||||
* specific content description.
|
||||
* specific learn more title.
|
||||
*
|
||||
* @return the content description for the help url
|
||||
* @return learn more title for the help url
|
||||
*/
|
||||
protected String getLearnMoreContentDescription() {
|
||||
return mLearnMoreContentDescription;
|
||||
protected String getLearnMoreText() {
|
||||
return mLearnMoreText;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,10 +117,13 @@ public class AccessibilityFooterPreferenceController extends BasePreferenceContr
|
||||
footerPreference.setLearnMoreAction(view -> {
|
||||
view.startActivityForResult(helpIntent, 0);
|
||||
});
|
||||
footerPreference.setLearnMoreContentDescription(getLearnMoreContentDescription());
|
||||
footerPreference.setLearnMoreText(getLearnMoreText());
|
||||
footerPreference.setLinkEnabled(true);
|
||||
} else {
|
||||
footerPreference.setLinkEnabled(false);
|
||||
}
|
||||
|
||||
// Grouping subcomponents to make more accessible.
|
||||
footerPreference.setSelectable(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RawRes;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -125,9 +126,15 @@ public final class AccessibilityGestureNavigationTutorial {
|
||||
}
|
||||
|
||||
static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes) {
|
||||
return createAccessibilityTutorialDialog(context, shortcutTypes, mOnClickListener);
|
||||
}
|
||||
|
||||
static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes,
|
||||
@Nullable DialogInterface.OnClickListener negativeButtonListener) {
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(createShortcutNavigationContentView(context, shortcutTypes))
|
||||
.setNegativeButton(R.string.accessibility_tutorial_dialog_button, mOnClickListener)
|
||||
.setNegativeButton(R.string.accessibility_tutorial_dialog_button,
|
||||
negativeButtonListener)
|
||||
.create();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,13 +38,15 @@ import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.HearingAidProfile;
|
||||
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 java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
@@ -53,7 +55,7 @@ import java.util.concurrent.FutureTask;
|
||||
* Controller that shows and updates the bluetooth device name
|
||||
*/
|
||||
public class AccessibilityHearingAidPreferenceController extends BasePreferenceController
|
||||
implements LifecycleObserver, OnStart, OnStop {
|
||||
implements LifecycleObserver, OnStart, OnStop, BluetoothCallback {
|
||||
private static final String TAG = "AccessibilityHearingAidPreferenceController";
|
||||
private Preference mHearingAidPreference;
|
||||
|
||||
@@ -82,15 +84,13 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
|
||||
|
||||
private final LocalBluetoothManager mLocalBluetoothManager;
|
||||
private final BluetoothAdapter mBluetoothAdapter;
|
||||
//cache value of supporting hearing aid or not
|
||||
private boolean mHearingAidProfileSupported;
|
||||
|
||||
private FragmentManager mFragmentManager;
|
||||
|
||||
public AccessibilityHearingAidPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mLocalBluetoothManager = getLocalBluetoothManager();
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
mHearingAidProfileSupported = isHearingAidProfileSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,29 +101,27 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mHearingAidProfileSupported ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
return isHearingAidProfileSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (mHearingAidProfileSupported) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
|
||||
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
mContext.registerReceiver(mHearingAidChangedReceiver, filter);
|
||||
}
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
|
||||
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
mContext.registerReceiver(mHearingAidChangedReceiver, filter);
|
||||
mLocalBluetoothManager.getEventManager().registerCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (mHearingAidProfileSupported) {
|
||||
mContext.unregisterReceiver(mHearingAidChangedReceiver);
|
||||
}
|
||||
mContext.unregisterReceiver(mHearingAidChangedReceiver);
|
||||
mLocalBluetoothManager.getEventManager().unregisterCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (TextUtils.equals(preference.getKey(), getPreferenceKey())){
|
||||
if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
|
||||
final CachedBluetoothDevice device = getConnectedHearingAidDevice();
|
||||
if (device == null) {
|
||||
launchHearingAidInstructionDialog();
|
||||
@@ -141,7 +139,38 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
|
||||
if (device == null) {
|
||||
return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
|
||||
}
|
||||
return device.getName();
|
||||
|
||||
final int connectedNum = getConnectedHearingAidDeviceNum();
|
||||
final CharSequence name = device.getName();
|
||||
final int side = device.getDeviceSide();
|
||||
final CachedBluetoothDevice subDevice = device.getSubDevice();
|
||||
if (connectedNum > 1) {
|
||||
return mContext.getString(R.string.accessibility_hearingaid_more_device_summary, name);
|
||||
}
|
||||
if (subDevice != null && subDevice.isConnected()) {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_hearingaid_left_and_right_side_device_summary, name);
|
||||
}
|
||||
if (side == HearingAidProfile.DeviceSide.SIDE_INVALID) {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_hearingaid_active_device_summary, name);
|
||||
}
|
||||
return (side == HearingAidProfile.DeviceSide.SIDE_LEFT)
|
||||
? mContext.getString(
|
||||
R.string.accessibility_hearingaid_left_side_device_summary, name)
|
||||
: mContext.getString(
|
||||
R.string.accessibility_hearingaid_right_side_device_summary, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
|
||||
if (activeDevice == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bluetoothProfile == BluetoothProfile.HEARING_AID) {
|
||||
HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, activeDevice);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFragmentManager(FragmentManager fragmentManager) {
|
||||
@@ -150,33 +179,44 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
|
||||
|
||||
@VisibleForTesting
|
||||
CachedBluetoothDevice getConnectedHearingAidDevice() {
|
||||
if (!mHearingAidProfileSupported) {
|
||||
if (!isHearingAidProfileSupported()) {
|
||||
return null;
|
||||
}
|
||||
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
final List<BluetoothDevice> deviceList = mLocalBluetoothManager.getProfileManager()
|
||||
.getHearingAidProfile().getConnectedDevices();
|
||||
final Iterator it = deviceList.iterator();
|
||||
while (it.hasNext()) {
|
||||
BluetoothDevice obj = (BluetoothDevice)it.next();
|
||||
if (!mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(obj)) {
|
||||
return mLocalBluetoothManager.getCachedDeviceManager().findDevice(obj);
|
||||
|
||||
final CachedBluetoothDeviceManager deviceManager =
|
||||
mLocalBluetoothManager.getCachedDeviceManager();
|
||||
final HearingAidProfile hearingAidProfile =
|
||||
mLocalBluetoothManager.getProfileManager().getHearingAidProfile();
|
||||
final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
|
||||
for (BluetoothDevice obj : deviceList) {
|
||||
if (!deviceManager.isSubDevice(obj)) {
|
||||
return deviceManager.findDevice(obj);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getConnectedHearingAidDeviceNum() {
|
||||
if (!isHearingAidProfileSupported()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final CachedBluetoothDeviceManager deviceManager =
|
||||
mLocalBluetoothManager.getCachedDeviceManager();
|
||||
final HearingAidProfile hearingAidProfile =
|
||||
mLocalBluetoothManager.getProfileManager().getHearingAidProfile();
|
||||
final List<BluetoothDevice> deviceList = hearingAidProfile.getConnectedDevices();
|
||||
return (int) deviceList.stream()
|
||||
.filter(device -> !deviceManager.isSubDevice(device))
|
||||
.count();
|
||||
}
|
||||
|
||||
private boolean isHearingAidProfileSupported() {
|
||||
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
|
||||
if (supportedList.contains(BluetoothProfile.HEARING_AID)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return supportedList.contains(BluetoothProfile.HEARING_AID);
|
||||
}
|
||||
|
||||
private LocalBluetoothManager getLocalBluetoothManager() {
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.content.SharedPreferences;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/** Provides utility methods to accessibility quick settings only. */
|
||||
final class AccessibilityQuickSettingUtils {
|
||||
|
||||
private static final String ACCESSIBILITY_PERF = "accessibility_prefs";
|
||||
private static final String KEY_TILE_SERVICE_SHOWN = "tile_service_shown";
|
||||
private static final char COMPONENT_NAME_SEPARATOR = ':';
|
||||
private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
|
||||
new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
|
||||
|
||||
/**
|
||||
* Opts in component name into {@link AccessibilityQuickSettingUtils#KEY_TILE_SERVICE_SHOWN}
|
||||
* colon-separated string in {@link SharedPreferences}.
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param componentName The component name that need to be opted in SharedPreferences.
|
||||
*/
|
||||
public static void optInValueToSharedPreferences(Context context,
|
||||
@NonNull ComponentName componentName) {
|
||||
final String targetString = getFromSharedPreferences(context);
|
||||
if (hasValueInSharedPreferences(targetString, componentName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
|
||||
if (!TextUtils.isEmpty(targetString)) {
|
||||
joiner.add(targetString);
|
||||
}
|
||||
joiner.add(componentName.flattenToString());
|
||||
|
||||
SharedPreferences.Editor editor = getSharedPreferences(context).edit();
|
||||
editor.putString(KEY_TILE_SERVICE_SHOWN, joiner.toString()).apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if component name existed in {@link
|
||||
* AccessibilityQuickSettingUtils#KEY_TILE_SERVICE_SHOWN} string in {@link SharedPreferences}.
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param componentName The component name that need to be checked existed in SharedPreferences.
|
||||
* @return {@code true} if componentName existed in SharedPreferences.
|
||||
*/
|
||||
public static boolean hasValueInSharedPreferences(Context context,
|
||||
@NonNull ComponentName componentName) {
|
||||
final String targetString = getFromSharedPreferences(context);
|
||||
return hasValueInSharedPreferences(targetString, componentName);
|
||||
}
|
||||
|
||||
private static boolean hasValueInSharedPreferences(String targetString,
|
||||
@NonNull ComponentName componentName) {
|
||||
if (TextUtils.isEmpty(targetString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sStringColonSplitter.setString(targetString);
|
||||
|
||||
while (sStringColonSplitter.hasNext()) {
|
||||
final String name = sStringColonSplitter.next();
|
||||
if (TextUtils.equals(componentName.flattenToString(), name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getFromSharedPreferences(Context context) {
|
||||
return getSharedPreferences(context).getString(KEY_TILE_SERVICE_SHOWN, "");
|
||||
}
|
||||
|
||||
private static SharedPreferences getSharedPreferences(Context context) {
|
||||
return context.getSharedPreferences(ACCESSIBILITY_PERF, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
private AccessibilityQuickSettingUtils(){}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.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.OnSaveInstanceState;
|
||||
|
||||
/** PrimarySwitchPreferenceController that shows quick settings tooltip on first use. */
|
||||
public abstract class AccessibilityQuickSettingsPrimarySwitchPreferenceController
|
||||
extends TogglePreferenceController
|
||||
implements LifecycleObserver, OnCreate, 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. */
|
||||
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 onSaveInstanceState(Bundle outState) {
|
||||
if (mTooltipWindow != null) {
|
||||
outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, mTooltipWindow.isShowing());
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.AccessibilityDelegate;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* UI container for the accessibility quick settings tooltip.
|
||||
*
|
||||
* <p> The popup window shows the information about the operation of the quick settings. In
|
||||
* addition, the arrow is pointing to the top center of the device to display one-off menu within
|
||||
* {@code mCloseDelayTimeMillis} time.</p>
|
||||
*/
|
||||
public class AccessibilityQuickSettingsTooltipWindow extends PopupWindow {
|
||||
|
||||
private final Context mContext;
|
||||
private Handler mHandler;
|
||||
private long mCloseDelayTimeMillis;
|
||||
|
||||
public AccessibilityQuickSettingsTooltipWindow(Context context) {
|
||||
super(context);
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
private final AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
final AccessibilityAction clickAction = new AccessibilityAction(
|
||||
AccessibilityNodeInfo.ACTION_CLICK,
|
||||
mContext.getString(R.string.accessibility_quick_settings_tooltip_dismiss));
|
||||
info.addAction(clickAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||
if (action == AccessibilityNodeInfo.ACTION_CLICK) {
|
||||
dismiss();
|
||||
return true;
|
||||
}
|
||||
return super.performAccessibilityAction(host, action, args);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Sets up {@link #AccessibilityQuickSettingsTooltipWindow}'s layout and content.
|
||||
*
|
||||
* @param text text to be displayed
|
||||
* @param imageResId the resource ID of the image drawable
|
||||
*/
|
||||
public void setup(CharSequence text, @DrawableRes int imageResId) {
|
||||
this.setup(text, imageResId, /* closeDelayTimeMillis= */ 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up {@link #AccessibilityQuickSettingsTooltipWindow}'s layout and content.
|
||||
*
|
||||
* <p> The system will attempt to close popup window to the target duration of the threads if
|
||||
* close delay time is positive number. </p>
|
||||
*
|
||||
* @param text text to be displayed
|
||||
* @param imageResId the resource ID of the image drawable
|
||||
* @param closeDelayTimeMillis how long the popup window be auto-closed
|
||||
*/
|
||||
public void setup(CharSequence text, @DrawableRes int imageResId, long closeDelayTimeMillis) {
|
||||
this.mCloseDelayTimeMillis = closeDelayTimeMillis;
|
||||
|
||||
setBackgroundDrawable(new ColorDrawable(mContext.getColor(android.R.color.transparent)));
|
||||
final LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
|
||||
final View popupView =
|
||||
inflater.inflate(R.layout.accessibility_qs_tooltip, /* root= */ null);
|
||||
popupView.setFocusable(/* focusable= */ true);
|
||||
popupView.setAccessibilityDelegate(mAccessibilityDelegate);
|
||||
setContentView(popupView);
|
||||
|
||||
final ImageView imageView = getContentView().findViewById(R.id.qs_illustration);
|
||||
imageView.setImageResource(imageResId);
|
||||
final TextView textView = getContentView().findViewById(R.id.qs_content);
|
||||
textView.setText(text);
|
||||
setWidth(getWindowWidthWith(textView));
|
||||
setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
setFocusable(/* focusable= */ true);
|
||||
setOutsideTouchable(/* touchable= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the content view in a popup window at the top and center position.
|
||||
*
|
||||
* @param targetView a target view to get the {@link View#getWindowToken()} token from.
|
||||
*/
|
||||
public void showAtTopCenter(View targetView) {
|
||||
showAtLocation(targetView, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes of the popup window.
|
||||
*
|
||||
* <p> Remove any pending posts of callbacks and sent messages for closing popup window. </p>
|
||||
*/
|
||||
@Override
|
||||
public void dismiss() {
|
||||
super.dismiss();
|
||||
if (mHandler != null) {
|
||||
mHandler.removeCallbacksAndMessages(/* token= */ null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the content view in a popup window at the specified location.
|
||||
*
|
||||
* <p> The system will attempt to close popup window to the target duration of the threads if
|
||||
* close delay time is positive number. </p>
|
||||
*
|
||||
* @param parent a parent view to get the {@link android.view.View#getWindowToken()} token from
|
||||
* @param gravity the gravity which controls the placement of the popup window
|
||||
* @param x the popup's x location offset
|
||||
* @param y the popup's y location offset
|
||||
*/
|
||||
@Override
|
||||
public void showAtLocation(View parent, int gravity, int x, int y) {
|
||||
super.showAtLocation(parent, gravity, x, y);
|
||||
scheduleAutoCloseAction();
|
||||
}
|
||||
|
||||
private void scheduleAutoCloseAction() {
|
||||
if (mCloseDelayTimeMillis <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHandler == null) {
|
||||
mHandler = new Handler(mContext.getMainLooper());
|
||||
}
|
||||
mHandler.removeCallbacksAndMessages(/* token= */ null);
|
||||
mHandler.postDelayed(this::dismiss, mCloseDelayTimeMillis);
|
||||
}
|
||||
|
||||
private int getWindowWidthWith(TextView textView) {
|
||||
final int availableWindowWidth = getAvailableWindowWidth();
|
||||
final int widthSpec =
|
||||
View.MeasureSpec.makeMeasureSpec(availableWindowWidth, View.MeasureSpec.AT_MOST);
|
||||
final int heightSpec =
|
||||
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
textView.measure(widthSpec, heightSpec);
|
||||
return textView.getMeasuredWidth();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int getAvailableWindowWidth() {
|
||||
final Resources res = mContext.getResources();
|
||||
final int padding = res.getDimensionPixelSize(R.dimen.accessibility_qs_tooltip_margin);
|
||||
final int screenWidth = res.getDisplayMetrics().widthPixels;
|
||||
return screenWidth - padding * 2;
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.core.SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.InstrumentedActivity;
|
||||
import com.android.settings.display.FontSizePreferenceFragmentForSetupWizard;
|
||||
import com.android.settings.display.ScreenZoomPreferenceFragmentForSetupWizard;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/** Settings font/display size activity for SUW. */
|
||||
public class AccessibilityScreenSizeForSetupWizardActivity extends InstrumentedActivity {
|
||||
private static final String TAG = "ScreenSizeForSetup";
|
||||
|
||||
// A parameter decides which fragment ({@link FontSizePreferenceFragmentForSetupWizard} or
|
||||
// {@link ScreenZoomPreferenceFragmentForSetupWizard}) will be visioned.
|
||||
static final String VISION_FRAGMENT_NO = "vision_fragment_no";
|
||||
/**
|
||||
* Flags indicating the type of the fragment.
|
||||
*/
|
||||
@IntDef({
|
||||
FragmentType.FONT_SIZE,
|
||||
FragmentType.SCREEN_SIZE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface FragmentType {
|
||||
int FONT_SIZE = 1;
|
||||
int SCREEN_SIZE = 2;
|
||||
}
|
||||
|
||||
// Keep the last height of the scroll view in the {@link GlifLayout}
|
||||
private int mLastScrollViewHeight;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final int appliedTheme = ThemeHelper.trySetDynamicColor(this)
|
||||
? R.style.SudDynamicColorThemeGlifV3_DayNight : R.style.SudThemeGlifV3_DayNight;
|
||||
setTheme(appliedTheme);
|
||||
setContentView(R.layout.accessibility_screen_size_setup_wizard);
|
||||
updateHeaderLayout();
|
||||
scrollToBottom();
|
||||
initFooterButton();
|
||||
if (savedInstanceState == null) {
|
||||
final PreferenceFragmentCompat fragment =
|
||||
getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? new FontSizePreferenceFragmentForSetupWizard()
|
||||
: new ScreenZoomPreferenceFragmentForSetupWizard();
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.content_frame, fragment)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
// For accessibility activities launched from setup wizard.
|
||||
if (getTransitionType(getIntent()) == TransitionType.TRANSITION_FADE) {
|
||||
overridePendingTransition(R.anim.sud_stay, android.R.anim.fade_out);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? SettingsEnums.SUW_ACCESSIBILITY_FONT_SIZE
|
||||
: SettingsEnums.SUW_ACCESSIBILITY_DISPLAY_SIZE;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateHeaderLayout() {
|
||||
if (ThemeHelper.shouldApplyExtendedPartnerConfig(this) && isSuwSupportedTwoPanes()) {
|
||||
final GlifLayout layout = findViewById(R.id.setup_wizard_layout);
|
||||
final LinearLayout headerLayout = layout.findManagedViewById(R.id.sud_layout_header);
|
||||
if (headerLayout != null) {
|
||||
headerLayout.setPadding(0, layout.getPaddingTop(), 0,
|
||||
layout.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
((TextView) findViewById(R.id.suc_layout_title)).setText(
|
||||
getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? R.string.title_font_size
|
||||
: R.string.screen_zoom_title);
|
||||
((TextView) findViewById(R.id.sud_layout_subtitle)).setText(
|
||||
getFragmentType(getIntent()) == FragmentType.FONT_SIZE
|
||||
? R.string.font_size_summary
|
||||
: R.string.screen_zoom_summary);
|
||||
}
|
||||
|
||||
private boolean isSuwSupportedTwoPanes() {
|
||||
return getResources().getBoolean(R.bool.config_suw_supported_two_panes);
|
||||
}
|
||||
|
||||
private void initFooterButton() {
|
||||
final GlifLayout layout = findViewById(R.id.setup_wizard_layout);
|
||||
final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
|
||||
final View.OnClickListener nextButtonListener = v -> onBackPressed();
|
||||
final FooterButton primaryButton =
|
||||
new FooterButton.Builder(this)
|
||||
.setText(R.string.done)
|
||||
.setListener(nextButtonListener)
|
||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build();
|
||||
mixin.setPrimaryButton(primaryButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls to bottom while {@link ScrollView} layout changed.
|
||||
*/
|
||||
private void scrollToBottom() {
|
||||
mLastScrollViewHeight = 0;
|
||||
final GlifLayout layout = findViewById(R.id.setup_wizard_layout);
|
||||
final ScrollView scrollView = layout.getScrollView();
|
||||
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
||||
final int scrollViewHeight = scrollView.getHeight();
|
||||
if (scrollViewHeight > 0 && scrollViewHeight != mLastScrollViewHeight) {
|
||||
mLastScrollViewHeight = scrollViewHeight;
|
||||
scrollView.post(() -> {
|
||||
// Here is no need to show the scrolling animation. So disabled first and
|
||||
// then enabled it after scrolling finished.
|
||||
scrollView.setSmoothScrollingEnabled(false);
|
||||
scrollView.fullScroll(View.FOCUS_DOWN);
|
||||
scrollView.setSmoothScrollingEnabled(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getTransitionType(Intent intent) {
|
||||
return intent.getIntExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_NONE);
|
||||
}
|
||||
|
||||
private int getFragmentType(Intent intent) {
|
||||
return intent.getIntExtra(VISION_FRAGMENT_NO, FragmentType.FONT_SIZE);
|
||||
}
|
||||
}
|
||||
@@ -16,21 +16,13 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.accessibilityservice.AccessibilityShortcutInfo;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
@@ -40,22 +32,17 @@ import android.util.ArrayMap;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
|
||||
import com.android.internal.accessibility.AccessibilityShortcutController;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.search.SearchIndexableRaw;
|
||||
|
||||
@@ -63,7 +50,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** Activity with the accessibility settings. */
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
@@ -71,9 +57,6 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "AccessibilitySettings";
|
||||
|
||||
// Index of the first preference in a preference category.
|
||||
private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1;
|
||||
|
||||
// Preference categories
|
||||
private static final String CATEGORY_SCREEN_READER = "screen_reader_category";
|
||||
private static final String CATEGORY_CAPTIONS = "captions_category";
|
||||
@@ -94,13 +77,16 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
static final String EXTRA_TITLE_RES = "title_res";
|
||||
static final String EXTRA_RESOLVE_INFO = "resolve_info";
|
||||
static final String EXTRA_SUMMARY = "summary";
|
||||
static final String EXTRA_INTRO = "intro";
|
||||
static final String EXTRA_SETTINGS_TITLE = "settings_title";
|
||||
static final String EXTRA_COMPONENT_NAME = "component_name";
|
||||
static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
|
||||
static final String EXTRA_TILE_SERVICE_COMPONENT_NAME = "tile_service_component_name";
|
||||
static final String EXTRA_VIDEO_RAW_RESOURCE_ID = "video_resource";
|
||||
static final String EXTRA_LAUNCHED_FROM_SUW = "from_suw";
|
||||
static final String EXTRA_ANIMATED_IMAGE_RES = "animated_image_res";
|
||||
static final String EXTRA_HTML_DESCRIPTION = "html_description";
|
||||
static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool";
|
||||
|
||||
// Timeout before we update the services if packages are added/removed
|
||||
// since the AccessibilityManagerService has to do that processing first
|
||||
@@ -146,7 +132,7 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
};
|
||||
|
||||
@VisibleForTesting
|
||||
final SettingsContentObserver mSettingsContentObserver;
|
||||
final AccessibilitySettingsContentObserver mSettingsContentObserver;
|
||||
|
||||
private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
|
||||
new ArrayMap<>();
|
||||
@@ -170,12 +156,9 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
// Observe changes from accessibility selection menu
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
mSettingsContentObserver = new SettingsContentObserver(mHandler, shortcutFeatureKeys) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
onContentChanged();
|
||||
}
|
||||
};
|
||||
mSettingsContentObserver = new AccessibilitySettingsContentObserver(mHandler);
|
||||
mSettingsContentObserver.registerKeysToObserverCallback(shortcutFeatureKeys,
|
||||
key -> onContentChanged());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,6 +186,12 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
registerContentMonitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateAllPreferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (mNeedPreferencesUpdate) {
|
||||
@@ -243,8 +232,7 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
* @param serviceEnabled Whether the accessibility service is enabled.
|
||||
* @return The service summary
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static CharSequence getServiceSummary(Context context, AccessibilityServiceInfo info,
|
||||
public static CharSequence getServiceSummary(Context context, AccessibilityServiceInfo info,
|
||||
boolean serviceEnabled) {
|
||||
if (serviceEnabled && info.crashed) {
|
||||
return context.getText(R.string.accessibility_summary_state_stopped);
|
||||
@@ -283,8 +271,7 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
* @param serviceEnabled Whether the accessibility service is enabled.
|
||||
* @return The service description
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static CharSequence getServiceDescription(Context context, AccessibilityServiceInfo info,
|
||||
public static CharSequence getServiceDescription(Context context, AccessibilityServiceInfo info,
|
||||
boolean serviceEnabled) {
|
||||
if (serviceEnabled && info.crashed) {
|
||||
return context.getText(R.string.accessibility_description_state_stopped);
|
||||
@@ -293,11 +280,6 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
return info.loadDescription(context.getPackageManager());
|
||||
}
|
||||
|
||||
static boolean isRampingRingerEnabled(final Context context) {
|
||||
return Settings.Global.getInt(
|
||||
context.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) == 1;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onContentChanged() {
|
||||
// If the fragment is visible then update preferences immediately, else set the flag then
|
||||
@@ -505,241 +487,4 @@ public class AccessibilitySettings extends DashboardFragment {
|
||||
context);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class helps setup RestrictedPreference.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static class RestrictedPreferenceHelper {
|
||||
private final Context mContext;
|
||||
private final DevicePolicyManager mDpm;
|
||||
private final PackageManager mPm;
|
||||
|
||||
RestrictedPreferenceHelper(Context context) {
|
||||
mContext = context;
|
||||
mDpm = context.getSystemService(DevicePolicyManager.class);
|
||||
mPm = context.getPackageManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the list of {@link RestrictedPreference} with the installedServices arguments.
|
||||
*
|
||||
* @param installedServices The list of {@link AccessibilityServiceInfo}s of the
|
||||
* installed accessibility services
|
||||
* @return The list of {@link RestrictedPreference}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
List<RestrictedPreference> createAccessibilityServicePreferenceList(
|
||||
List<AccessibilityServiceInfo> installedServices) {
|
||||
|
||||
final Set<ComponentName> enabledServices =
|
||||
AccessibilityUtils.getEnabledServicesFromSettings(mContext);
|
||||
final List<String> permittedServices = mDpm.getPermittedAccessibilityServices(
|
||||
UserHandle.myUserId());
|
||||
final int installedServicesSize = installedServices.size();
|
||||
|
||||
final List<RestrictedPreference> preferenceList = new ArrayList<>(
|
||||
installedServicesSize);
|
||||
|
||||
for (int i = 0; i < installedServicesSize; ++i) {
|
||||
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 String key = componentName.flattenToString();
|
||||
final CharSequence title = resolveInfo.loadLabel(mPm);
|
||||
final boolean serviceEnabled = enabledServices.contains(componentName);
|
||||
final CharSequence summary = getServiceSummary(mContext, info, serviceEnabled);
|
||||
final String fragment = getAccessibilityServiceFragmentTypeName(info);
|
||||
|
||||
Drawable icon = resolveInfo.loadIcon(mPm);
|
||||
if (resolveInfo.getIconResource() == 0) {
|
||||
icon = ContextCompat.getDrawable(mContext,
|
||||
R.drawable.ic_accessibility_generic);
|
||||
}
|
||||
|
||||
final RestrictedPreference preference = createRestrictedPreference(key, title,
|
||||
summary, icon, fragment);
|
||||
|
||||
// permittedServices null means all accessibility services are allowed.
|
||||
final boolean serviceAllowed =
|
||||
permittedServices == null || permittedServices.contains(packageName);
|
||||
|
||||
setRestrictedPreferenceEnabled(preference, packageName, serviceAllowed,
|
||||
serviceEnabled);
|
||||
final String prefKey = preference.getKey();
|
||||
final int imageRes = info.getAnimatedImageRes();
|
||||
final CharSequence description = getServiceDescription(mContext, info,
|
||||
serviceEnabled);
|
||||
final String htmlDescription = info.loadHtmlDescription(mPm);
|
||||
final String settingsClassName = info.getSettingsActivityName();
|
||||
|
||||
putBasicExtras(preference, prefKey, title, description, imageRes, htmlDescription,
|
||||
componentName);
|
||||
putServiceExtras(preference, resolveInfo, serviceEnabled);
|
||||
putSettingsExtras(preference, packageName, settingsClassName);
|
||||
|
||||
preferenceList.add(preference);
|
||||
}
|
||||
return preferenceList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the list of {@link RestrictedPreference} with the installedShortcuts arguments.
|
||||
*
|
||||
* @param installedShortcuts The list of {@link AccessibilityShortcutInfo}s of the
|
||||
* installed accessibility shortcuts
|
||||
* @return The list of {@link RestrictedPreference}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
List<RestrictedPreference> 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<RestrictedPreference> preferenceList = new ArrayList<>(
|
||||
installedShortcutsSize);
|
||||
|
||||
for (int i = 0; i < installedShortcutsSize; ++i) {
|
||||
final AccessibilityShortcutInfo info = installedShortcuts.get(i);
|
||||
final ActivityInfo activityInfo = info.getActivityInfo();
|
||||
final ComponentName componentName = info.getComponentName();
|
||||
|
||||
final String key = componentName.flattenToString();
|
||||
final CharSequence title = activityInfo.loadLabel(mPm);
|
||||
final String summary = info.loadSummary(mPm);
|
||||
final String fragment =
|
||||
LaunchAccessibilityActivityPreferenceFragment.class.getName();
|
||||
|
||||
Drawable icon = activityInfo.loadIcon(mPm);
|
||||
if (activityInfo.getIconResource() == 0) {
|
||||
icon = ContextCompat.getDrawable(mContext, R.drawable.ic_accessibility_generic);
|
||||
}
|
||||
|
||||
final RestrictedPreference preference = createRestrictedPreference(key, title,
|
||||
summary, icon, fragment);
|
||||
|
||||
final String packageName = componentName.getPackageName();
|
||||
// permittedServices null means all accessibility services are allowed.
|
||||
final boolean serviceAllowed =
|
||||
permittedServices == null || permittedServices.contains(packageName);
|
||||
final boolean serviceEnabled = enabledServices.contains(componentName);
|
||||
|
||||
setRestrictedPreferenceEnabled(preference, packageName, serviceAllowed,
|
||||
serviceEnabled);
|
||||
|
||||
final String prefKey = preference.getKey();
|
||||
final String description = info.loadDescription(mPm);
|
||||
final int imageRes = info.getAnimatedImageRes();
|
||||
final String htmlDescription = info.loadHtmlDescription(mPm);
|
||||
final String settingsClassName = info.getSettingsActivityName();
|
||||
|
||||
putBasicExtras(preference, prefKey, title, description, imageRes, htmlDescription,
|
||||
componentName);
|
||||
putSettingsExtras(preference, packageName, settingsClassName);
|
||||
|
||||
preferenceList.add(preference);
|
||||
}
|
||||
return preferenceList;
|
||||
}
|
||||
|
||||
private String getAccessibilityServiceFragmentTypeName(AccessibilityServiceInfo info) {
|
||||
// Shorten the name to avoid exceeding 100 characters in one line.
|
||||
final String volumeShortcutToggleAccessibilityServicePreferenceFragment =
|
||||
VolumeShortcutToggleAccessibilityServicePreferenceFragment.class.getName();
|
||||
|
||||
switch (AccessibilityUtil.getAccessibilityServiceFragmentType(info)) {
|
||||
case AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE:
|
||||
return volumeShortcutToggleAccessibilityServicePreferenceFragment;
|
||||
case AccessibilityServiceFragmentType.INVISIBLE_TOGGLE:
|
||||
return InvisibleToggleAccessibilityServicePreferenceFragment.class.getName();
|
||||
case AccessibilityServiceFragmentType.TOGGLE:
|
||||
return ToggleAccessibilityServicePreferenceFragment.class.getName();
|
||||
default:
|
||||
// impossible status
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private RestrictedPreference createRestrictedPreference(String key, CharSequence title,
|
||||
CharSequence summary, Drawable icon, String fragment) {
|
||||
final RestrictedPreference preference = new RestrictedPreference(mContext);
|
||||
|
||||
preference.setKey(key);
|
||||
preference.setTitle(title);
|
||||
preference.setSummary(summary);
|
||||
preference.setIcon(Utils.getAdaptiveIcon(mContext, icon, Color.WHITE));
|
||||
preference.setFragment(fragment);
|
||||
preference.setIconSize(ICON_SIZE_MEDIUM);
|
||||
preference.setPersistent(false); // Disable SharedPreferences.
|
||||
preference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
|
||||
|
||||
return preference;
|
||||
}
|
||||
|
||||
private void setRestrictedPreferenceEnabled(RestrictedPreference preference,
|
||||
String packageName, boolean serviceAllowed, boolean serviceEnabled) {
|
||||
if (serviceAllowed || serviceEnabled) {
|
||||
preference.setEnabled(true);
|
||||
} else {
|
||||
// Disable accessibility service that are not permitted.
|
||||
final EnforcedAdmin admin =
|
||||
RestrictedLockUtilsInternal.checkIfAccessibilityServiceDisallowed(
|
||||
mContext, packageName, UserHandle.myUserId());
|
||||
if (admin != null) {
|
||||
preference.setDisabledByAdmin(admin);
|
||||
} else {
|
||||
preference.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Puts the basic extras into {@link RestrictedPreference}'s getExtras(). */
|
||||
private void putBasicExtras(RestrictedPreference preference, String prefKey,
|
||||
CharSequence title, CharSequence summary, int imageRes, String htmlDescription,
|
||||
ComponentName componentName) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
extras.putString(EXTRA_PREFERENCE_KEY, prefKey);
|
||||
extras.putCharSequence(EXTRA_TITLE, title);
|
||||
extras.putCharSequence(EXTRA_SUMMARY, summary);
|
||||
extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
|
||||
extras.putInt(EXTRA_ANIMATED_IMAGE_RES, imageRes);
|
||||
extras.putString(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, htmlDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the service extras into {@link RestrictedPreference}'s getExtras().
|
||||
*
|
||||
* Called by {@link AccessibilityServiceInfo} for now.
|
||||
*/
|
||||
private void putServiceExtras(RestrictedPreference preference, ResolveInfo resolveInfo,
|
||||
Boolean serviceEnabled) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
|
||||
extras.putParcelable(EXTRA_RESOLVE_INFO, resolveInfo);
|
||||
extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the settings extras into {@link RestrictedPreference}'s getExtras().
|
||||
*
|
||||
* Called when settings UI is needed.
|
||||
*/
|
||||
private void putSettingsExtras(RestrictedPreference preference, String packageName,
|
||||
String settingsClassName) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
|
||||
if (!TextUtils.isEmpty(settingsClassName)) {
|
||||
extras.putString(EXTRA_SETTINGS_TITLE,
|
||||
mContext.getText(R.string.accessibility_menu_item_settings).toString());
|
||||
extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
|
||||
new ComponentName(packageName, settingsClassName).flattenToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.ContentResolver;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class AccessibilitySettingsContentObserver extends ContentObserver {
|
||||
|
||||
private static final String TAG = "AccessibilitySettingsContentObserver";
|
||||
|
||||
public interface ContentObserverCallback {
|
||||
void onChange(String key);
|
||||
}
|
||||
|
||||
// Key: Preference key's uri, Value: Preference key
|
||||
private final Map<Uri, String> mUriToKey = new HashMap<>(2);
|
||||
|
||||
// Key: Collection of preference keys, Value: onChange callback for keys
|
||||
private final Map<List<String>, ContentObserverCallback> mUrisToCallback = new HashMap<>();
|
||||
|
||||
AccessibilitySettingsContentObserver(Handler handler) {
|
||||
super(handler);
|
||||
|
||||
// default key to be observed
|
||||
addDefaultKeysToMap();
|
||||
}
|
||||
|
||||
public void register(ContentResolver contentResolver) {
|
||||
for (Uri uri : mUriToKey.keySet()) {
|
||||
contentResolver.registerContentObserver(uri, false, this);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregister(ContentResolver contentResolver) {
|
||||
contentResolver.unregisterContentObserver(this);
|
||||
}
|
||||
|
||||
private void addDefaultKeysToMap() {
|
||||
addKeyToMap(Settings.Secure.ACCESSIBILITY_ENABLED);
|
||||
addKeyToMap(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
|
||||
}
|
||||
|
||||
private boolean isDefaultKey(String key) {
|
||||
return Settings.Secure.ACCESSIBILITY_ENABLED.equals(key)
|
||||
|| Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(key);
|
||||
}
|
||||
|
||||
private void addKeyToMap(String key) {
|
||||
mUriToKey.put(Settings.Secure.getUriFor(key), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ContentObserverCallback} is added to {@link ContentObserver} to handle the
|
||||
* onChange event triggered by the key collection of {@code keysToObserve} and the default
|
||||
* keys.
|
||||
*
|
||||
* Note: The following key are default to be observed.
|
||||
* {@link Settings.Secure.ACCESSIBILITY_ENABLED}
|
||||
* {@link Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES}
|
||||
*
|
||||
* @param keysToObserve A collection of keys which are going to be observed.
|
||||
* @param observerCallback A callback which is used to handle the onChange event triggered
|
||||
* by the key collection of {@code keysToObserve}.
|
||||
*/
|
||||
public void registerKeysToObserverCallback(List<String> keysToObserve,
|
||||
ContentObserverCallback observerCallback) {
|
||||
|
||||
for (String key: keysToObserve) {
|
||||
addKeyToMap(key);
|
||||
}
|
||||
|
||||
mUrisToCallback.put(keysToObserve, observerCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ContentObserverCallback} is added to {@link ContentObserver} to handle the
|
||||
* onChange event triggered by the default keys.
|
||||
*
|
||||
* Note: The following key are default to be observed.
|
||||
* {@link Settings.Secure.ACCESSIBILITY_ENABLED}
|
||||
* {@link Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES}
|
||||
*
|
||||
* @param observerCallback A callback which is used to handle the onChange event triggered
|
||||
* * by the key collection of {@code keysToObserve}.
|
||||
*/
|
||||
public void registerObserverCallback(ContentObserverCallback observerCallback) {
|
||||
mUrisToCallback.put(Collections.emptyList(), observerCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onChange(boolean selfChange, Uri uri) {
|
||||
|
||||
final String key = mUriToKey.get(uri);
|
||||
|
||||
if (key == null) {
|
||||
Log.w(TAG, "AccessibilitySettingsContentObserver can not find the key for "
|
||||
+ "uri: " + uri);
|
||||
return;
|
||||
}
|
||||
|
||||
for (List<String> keys : mUrisToCallback.keySet()) {
|
||||
final boolean isDefaultKey = isDefaultKey(key);
|
||||
if (isDefaultKey || keys.contains(key)) {
|
||||
mUrisToCallback.get(keys).onChange(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,7 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.VISION_FRAGMENT_NO;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
@@ -32,19 +27,16 @@ import androidx.preference.PreferenceFragmentCompat;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.FragmentType;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.search.actionbar.SearchMenuController;
|
||||
import com.android.settings.support.actionbar.HelpResourceProvider;
|
||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
public class AccessibilitySettingsForSetupWizardActivity extends SettingsActivity {
|
||||
|
||||
private static final String LOG_TAG = "A11ySettingsForSUW";
|
||||
private static final String SAVE_KEY_TITLE = "activity_title";
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -105,33 +97,12 @@ public class AccessibilitySettingsForSetupWizardActivity extends SettingsActivit
|
||||
protected void onCreate(Bundle savedState) {
|
||||
super.onCreate(savedState);
|
||||
applyTheme();
|
||||
tryLaunchFontSizeSettings();
|
||||
findViewById(R.id.content_parent).setFitsSystemWindows(false);
|
||||
}
|
||||
|
||||
private void applyTheme() {
|
||||
if (ThemeHelper.trySetDynamicColor(this)) {
|
||||
final int appliedTheme = ThemeHelper.isSetupWizardDayNightEnabled(this)
|
||||
? R.style.SudDynamicColorThemeSettings_SetupWizard_DayNight
|
||||
: R.style.SudDynamicColorThemeSettings_SetupWizard;
|
||||
setTheme(appliedTheme);
|
||||
} else {
|
||||
setTheme(SetupWizardUtils.getTheme(this, getIntent()));
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void tryLaunchFontSizeSettings() {
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent())
|
||||
&& new ComponentName(getPackageName(),
|
||||
CLASS_NAME_FONT_SIZE_SETTINGS_FOR_SUW).equals(
|
||||
getIntent().getComponent())) {
|
||||
final Intent intent = new Intent(this,
|
||||
AccessibilityScreenSizeForSetupWizardActivity.class);
|
||||
intent.putExtra(VISION_FRAGMENT_NO, FragmentType.FONT_SIZE);
|
||||
startActivity(intent);
|
||||
Log.d(LOG_TAG, "Launch font size settings");
|
||||
finish();
|
||||
}
|
||||
setTheme(SetupWizardUtils.getTheme(this, getIntent()));
|
||||
setTheme(R.style.SettingsPreferenceTheme_SetupWizard);
|
||||
ThemeHelper.trySetDynamicColor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class AccessibilitySetupWizardUtils {
|
||||
layout.setIcon(icon);
|
||||
layout.setDividerInsets(Integer.MAX_VALUE, 0);
|
||||
|
||||
if (ThemeHelper.shouldApplyExtendedPartnerConfig(context)) {
|
||||
if (ThemeHelper.shouldApplyMaterialYouStyle(context)) {
|
||||
final LinearLayout headerLayout = layout.findManagedViewById(R.id.sud_layout_header);
|
||||
if (headerLayout != null) {
|
||||
headerLayout.setPadding(0, layout.getPaddingTop(), 0,
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
|
||||
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_GENERAL_CATEGORY;
|
||||
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_SAVED_QS_TOOLTIP_TYPE;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
@@ -25,10 +26,10 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.icu.text.CaseMap;
|
||||
import android.net.Uri;
|
||||
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;
|
||||
@@ -41,6 +42,7 @@ import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
|
||||
@@ -57,6 +59,7 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
implements ShortcutPreference.OnClickCallback {
|
||||
private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
|
||||
protected static final String KEY_SAVED_USER_SHORTCUT_TYPE = "shortcut_type";
|
||||
protected static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
|
||||
protected static final int NOT_SET = -1;
|
||||
// Save user's shortcutType value when savedInstance has value (e.g. device rotated).
|
||||
protected int mSavedCheckBoxValue = NOT_SET;
|
||||
@@ -64,9 +67,12 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
protected ShortcutPreference mShortcutPreference;
|
||||
private AccessibilityManager.TouchExplorationStateChangeListener
|
||||
mTouchExplorationStateChangeListener;
|
||||
private SettingsContentObserver mSettingsContentObserver;
|
||||
private AccessibilitySettingsContentObserver mSettingsContentObserver;
|
||||
private CheckBox mSoftwareTypeCheckBox;
|
||||
private CheckBox mHardwareTypeCheckBox;
|
||||
private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
|
||||
private boolean mNeedsQSTooltipReshow = false;
|
||||
private int mNeedsQSTooltipType = QuickSettingsTooltipType.GUIDE_TO_EDIT;
|
||||
|
||||
/** Returns the accessibility component name. */
|
||||
protected abstract ComponentName getComponentName();
|
||||
@@ -74,14 +80,28 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
/** Returns the accessibility feature name. */
|
||||
protected abstract CharSequence getLabelName();
|
||||
|
||||
/** Returns the accessibility tile component name. */
|
||||
protected abstract ComponentName getTileComponentName();
|
||||
|
||||
/** Returns the accessibility tile tooltip content. */
|
||||
protected abstract CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Restore the user shortcut type.
|
||||
if (savedInstanceState != null && savedInstanceState.containsKey(
|
||||
KEY_SAVED_USER_SHORTCUT_TYPE)) {
|
||||
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE, NOT_SET);
|
||||
// Restore the user shortcut type and tooltip.
|
||||
if (savedInstanceState != null) {
|
||||
if (savedInstanceState.containsKey(KEY_SAVED_USER_SHORTCUT_TYPE)) {
|
||||
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE,
|
||||
NOT_SET);
|
||||
}
|
||||
if (savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_RESHOW)) {
|
||||
mNeedsQSTooltipReshow = savedInstanceState.getBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW);
|
||||
}
|
||||
if (savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_TYPE)) {
|
||||
mNeedsQSTooltipType = savedInstanceState.getInt(KEY_SAVED_QS_TOOLTIP_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
final int resId = getPreferenceScreenResId();
|
||||
@@ -98,13 +118,11 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
final List<String> shortcutFeatureKeys = new ArrayList<>();
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
mSettingsContentObserver = new SettingsContentObserver(new Handler(), shortcutFeatureKeys) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
updateShortcutPreferenceData();
|
||||
updateShortcutPreference();
|
||||
}
|
||||
};
|
||||
mSettingsContentObserver = new AccessibilitySettingsContentObserver(new Handler());
|
||||
mSettingsContentObserver.registerKeysToObserverCallback(shortcutFeatureKeys, key -> {
|
||||
updateShortcutPreferenceData();
|
||||
updateShortcutPreference();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,8 +132,8 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
mShortcutPreference.setPersistent(false);
|
||||
mShortcutPreference.setKey(getShortcutPreferenceKey());
|
||||
mShortcutPreference.setOnClickCallback(this);
|
||||
mShortcutPreference.setTitle(getShortcutTitle());
|
||||
|
||||
updateShortcutTitle(mShortcutPreference);
|
||||
getPreferenceScreen().addPreference(mShortcutPreference);
|
||||
|
||||
mTouchExplorationStateChangeListener = isTouchExplorationEnabled -> {
|
||||
@@ -126,6 +144,16 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// Reshow tooltip when activity recreate, such as rotate device.
|
||||
if (mNeedsQSTooltipReshow) {
|
||||
getView().post(this::showQuickSettingsTooltipIfNeeded);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -152,6 +180,10 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
if (value != NOT_SET) {
|
||||
outState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, value);
|
||||
}
|
||||
if (mTooltipWindow != null) {
|
||||
outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, mTooltipWindow.isShowing());
|
||||
outState.putInt(KEY_SAVED_QS_TOOLTIP_TYPE, mNeedsQSTooltipType);
|
||||
}
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@@ -160,20 +192,18 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
final Dialog dialog;
|
||||
switch (dialogId) {
|
||||
case DialogEnums.EDIT_SHORTCUT:
|
||||
final CharSequence dialogTitle = getPrefContext().getString(
|
||||
R.string.accessibility_shortcut_title, getLabelName());
|
||||
final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
|
||||
? AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC_SUW :
|
||||
AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC;
|
||||
dialog = AccessibilityDialogUtils.showEditShortcutDialog(
|
||||
getPrefContext(), dialogType, dialogTitle,
|
||||
getPrefContext(), dialogType, getShortcutTitle(),
|
||||
this::callOnAlertDialogCheckboxClicked);
|
||||
setupEditShortcutDialog(dialog);
|
||||
return dialog;
|
||||
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
|
||||
dialog = AccessibilityGestureNavigationTutorial
|
||||
.createAccessibilityTutorialDialog(getPrefContext(),
|
||||
getUserShortcutTypes());
|
||||
getUserShortcutTypes(), this::callOnTutorialDialogButtonClicked);
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
return dialog;
|
||||
default:
|
||||
@@ -181,9 +211,8 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
final CharSequence title = getString(R.string.accessibility_shortcut_title, getLabelName());
|
||||
shortcutPreference.setTitle(title);
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getString(R.string.accessibility_shortcut_title, getLabelName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,6 +300,17 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
getComponentName());
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will be invoked when a button in the tutorial dialog is clicked.
|
||||
*
|
||||
* @param dialog The dialog that received the click
|
||||
* @param which The button that was clicked
|
||||
*/
|
||||
private void callOnTutorialDialogButtonClicked(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be invoked when a button in the edit shortcut dialog is clicked.
|
||||
*
|
||||
@@ -283,12 +323,21 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
}
|
||||
|
||||
final int value = getShortcutTypeCheckBoxValue();
|
||||
|
||||
saveNonEmptyUserShortcutType(value);
|
||||
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), value, getComponentName());
|
||||
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~value, getComponentName());
|
||||
mShortcutPreference.setChecked(value != AccessibilityUtil.UserShortcutType.EMPTY);
|
||||
final boolean shortcutAssigned = value != AccessibilityUtil.UserShortcutType.EMPTY;
|
||||
mShortcutPreference.setChecked(shortcutAssigned);
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
|
||||
if (mHardwareTypeCheckBox.isChecked()) {
|
||||
AccessibilityUtil.skipVolumeShortcutDialogTimeoutRestriction(getPrefContext());
|
||||
}
|
||||
|
||||
// Show the quick setting tooltip if the shortcut assigned in the first time
|
||||
if (shortcutAssigned) {
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -426,4 +475,45 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
|
||||
getComponentName()));
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the quick settings tooltip if the quick settings feature is assigned. The tooltip only
|
||||
* shows once.
|
||||
*
|
||||
* @param type The quick settings tooltip type
|
||||
*/
|
||||
protected void showQuickSettingsTooltipIfNeeded(@QuickSettingsTooltipType int type) {
|
||||
mNeedsQSTooltipType = type;
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
|
||||
private void showQuickSettingsTooltipIfNeeded() {
|
||||
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,6 +16,16 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.BOLD_TEXT_KEY;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.DISPLAY_SIZE_KEY;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint.ACCESSIBILITY_SETTINGS;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint.DISPLAY_SETTINGS;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint.SUW_ANYTHING_ELSE;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint.SUW_VISION_SETTINGS;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.FONT_SIZE_KEY;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.HIGH_TEXT_CONTRAST_KEY;
|
||||
import static com.android.settings.accessibility.TextReadingPreferenceFragment.RESET_KEY;
|
||||
|
||||
import android.content.ComponentName;
|
||||
|
||||
import com.android.settings.core.instrumentation.SettingsStatsLog;
|
||||
@@ -41,4 +51,65 @@ public final class AccessibilityStatsLogUtils {
|
||||
return enabled ? SettingsStatsLog.ACCESSIBILITY_SERVICE_REPORTED__SERVICE_STATUS__ENABLED
|
||||
: SettingsStatsLog.ACCESSIBILITY_SERVICE_REPORTED__SERVICE_STATUS__DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs when the non-a11y category service is disabled. Calls this when the user disables the
|
||||
* non-a11y category service for the first time.
|
||||
*
|
||||
* @param packageName package name of the service
|
||||
* @param durationMills duration in milliseconds between starting the page and disabling the
|
||||
* service
|
||||
*/
|
||||
static void logDisableNonA11yCategoryService(String packageName, long durationMills) {
|
||||
com.android.internal.accessibility.util.AccessibilityStatsLogUtils
|
||||
.logNonA11yToolServiceWarningReported(
|
||||
packageName,
|
||||
com.android.internal.accessibility.util.AccessibilityStatsLogUtils
|
||||
.ACCESSIBILITY_PRIVACY_WARNING_STATUS_SERVICE_DISABLED,
|
||||
durationMills);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to the key name for logging.
|
||||
*
|
||||
* @param prefKey the preference key
|
||||
* @return the int value which maps to the key name
|
||||
*/
|
||||
static int convertToItemKeyName(String prefKey) {
|
||||
switch (prefKey) {
|
||||
case FONT_SIZE_KEY:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__NAME__TEXT_READING_FONT_SIZE;
|
||||
case DISPLAY_SIZE_KEY:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__NAME__TEXT_READING_DISPLAY_SIZE;
|
||||
case BOLD_TEXT_KEY:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__NAME__TEXT_READING_BOLD_TEXT;
|
||||
case HIGH_TEXT_CONTRAST_KEY:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__NAME__TEXT_READING_HIGH_CONTRAST_TEXT;
|
||||
case RESET_KEY:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__NAME__TEXT_READING_RESET;
|
||||
default:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__NAME__TEXT_READING_UNKNOWN_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to the entry point for logging.
|
||||
*
|
||||
* @param entryPoint the entry point
|
||||
* @return the int value which maps to the entry point
|
||||
*/
|
||||
static int convertToEntryPoint(int entryPoint) {
|
||||
switch (entryPoint) {
|
||||
case SUW_VISION_SETTINGS:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__ENTRY_POINT__TEXT_READING_SUW_VISION_SETTINGS;
|
||||
case SUW_ANYTHING_ELSE:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__ENTRY_POINT__TEXT_READING_SUW_ANYTHING_ELSE;
|
||||
case DISPLAY_SETTINGS:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__ENTRY_POINT__TEXT_READING_DISPLAY_SETTINGS;
|
||||
case ACCESSIBILITY_SETTINGS:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__ENTRY_POINT__TEXT_READING_ACCESSIBILITY_SETTINGS;
|
||||
default:
|
||||
return SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED__ENTRY_POINT__TEXT_READING_UNKNOWN_ENTRY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.widget.RadioButtonPreference;
|
||||
import com.android.settingslib.widget.SelectorWithWidgetPreference;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
@@ -40,7 +40,7 @@ import java.util.Map;
|
||||
* Controller class that control accessibility time out settings.
|
||||
*/
|
||||
public class AccessibilityTimeoutController extends AbstractPreferenceController implements
|
||||
LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin {
|
||||
LifecycleObserver, SelectorWithWidgetPreference.OnClickListener, PreferenceControllerMixin {
|
||||
static final String CONTENT_TIMEOUT_SETTINGS_SECURE =
|
||||
Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS;
|
||||
static final String CONTROL_TIMEOUT_SETTINGS_SECURE =
|
||||
@@ -54,7 +54,7 @@ public class AccessibilityTimeoutController extends AbstractPreferenceController
|
||||
private final ContentResolver mContentResolver;
|
||||
private final Resources mResources;
|
||||
private OnChangeListener mOnChangeListener;
|
||||
private RadioButtonPreference mPreference;
|
||||
private SelectorWithWidgetPreference mPreference;
|
||||
private int mAccessibilityUiTimeoutValue;
|
||||
|
||||
public AccessibilityTimeoutController(Context context, Lifecycle lifecycle,
|
||||
@@ -124,13 +124,13 @@ public class AccessibilityTimeoutController extends AbstractPreferenceController
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mPreference = (RadioButtonPreference)
|
||||
mPreference = (SelectorWithWidgetPreference)
|
||||
screen.findPreference(getPreferenceKey());
|
||||
mPreference.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRadioButtonClicked(RadioButtonPreference preference) {
|
||||
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
|
||||
int value = getTimeoutValueToKeyMap().get(mPreferenceKey);
|
||||
handlePreferenceChange(String.valueOf(value));
|
||||
if (mOnChangeListener != null) {
|
||||
|
||||
@@ -46,7 +46,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/** Provides utility methods to accessibility settings only. */
|
||||
final class AccessibilityUtil {
|
||||
public final class AccessibilityUtil {
|
||||
|
||||
private AccessibilityUtil(){}
|
||||
|
||||
@@ -105,6 +105,17 @@ final class AccessibilityUtil {
|
||||
int TRIPLETAP = 4; // 1 << 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Denotes the quick setting tooltip type.
|
||||
*
|
||||
* {@code GUIDE_TO_EDIT} for QS tiles that need to be added by editing.
|
||||
* {@code GUIDE_TO_DIRECT_USE} for QS tiles that have been auto-added already.
|
||||
*/
|
||||
public @interface QuickSettingsTooltipType {
|
||||
int GUIDE_TO_EDIT = 0;
|
||||
int GUIDE_TO_DIRECT_USE = 1;
|
||||
}
|
||||
|
||||
/** Denotes the accessibility enabled status */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface State {
|
||||
@@ -423,4 +434,15 @@ final class AccessibilityUtil {
|
||||
public static boolean isSystemApp(@NonNull AccessibilityServiceInfo info) {
|
||||
return info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bypasses the timeout restriction if volume key shortcut assigned.
|
||||
*
|
||||
* @param context the current context.
|
||||
*/
|
||||
public static void skipVolumeShortcutDialogTimeoutRestriction(Context context) {
|
||||
Settings.Secure.putInt(context.getContentResolver(),
|
||||
Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, /*
|
||||
true */ 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.provider.Settings;
|
||||
|
||||
/** Preference controller for alarm vibration intensity */
|
||||
public class AlarmVibrationIntensityPreferenceController
|
||||
extends VibrationIntensityPreferenceController {
|
||||
|
||||
/** General configuration for alarm vibration intensity settings. */
|
||||
public static final class AlarmVibrationPreferenceConfig extends VibrationPreferenceConfig {
|
||||
|
||||
public AlarmVibrationPreferenceConfig(Context context) {
|
||||
super(context, Settings.System.ALARM_VIBRATION_INTENSITY,
|
||||
VibrationAttributes.USAGE_ALARM);
|
||||
}
|
||||
}
|
||||
|
||||
public AlarmVibrationIntensityPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new AlarmVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
protected AlarmVibrationIntensityPreferenceController(Context context, String preferenceKey,
|
||||
int supportedIntensityLevels) {
|
||||
super(context, preferenceKey, new AlarmVibrationPreferenceConfig(context),
|
||||
supportedIntensityLevels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
|
||||
import com.android.settings.accessibility.AlarmVibrationIntensityPreferenceController.AlarmVibrationPreferenceConfig;
|
||||
|
||||
/** Preference controller for alarm vibration with only a toggle for on/off states. */
|
||||
public class AlarmVibrationTogglePreferenceController extends VibrationTogglePreferenceController {
|
||||
|
||||
public AlarmVibrationTogglePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new AlarmVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/**
|
||||
* A toggle preference controller for audio description
|
||||
*/
|
||||
public class AudioDescriptionPreferenceController extends TogglePreferenceController {
|
||||
|
||||
static final String PREF_KEY = "toggle_audio_description";
|
||||
|
||||
public AudioDescriptionPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
|
||||
ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
|
||||
OFF /* default */,
|
||||
UserHandle.USER_CURRENT) == ON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
return Settings.Secure.putIntForUser(mContext.getContentResolver(),
|
||||
ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
|
||||
isChecked ? ON : OFF,
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,16 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.CaptioningManager;
|
||||
@@ -92,6 +96,7 @@ public class CaptionAppearanceFragment extends DashboardFragment
|
||||
|
||||
private final List<Preference> mPreferenceList = new ArrayList<>();
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
private final View.OnLayoutChangeListener mLayoutChangeListener =
|
||||
new View.OnLayoutChangeListener() {
|
||||
@Override
|
||||
@@ -99,7 +104,7 @@ public class CaptionAppearanceFragment extends DashboardFragment
|
||||
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
// Remove the listener once the callback is triggered.
|
||||
mPreviewViewport.removeOnLayoutChangeListener(this);
|
||||
refreshPreviewText();
|
||||
mHandler.post(() ->refreshPreviewText());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -397,6 +402,7 @@ public class CaptionAppearanceFragment extends DashboardFragment
|
||||
}
|
||||
|
||||
refreshPreviewText();
|
||||
enableCaptioningManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -406,16 +412,26 @@ public class CaptionAppearanceFragment extends DashboardFragment
|
||||
Settings.Secure.putString(
|
||||
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE, (String) value);
|
||||
refreshPreviewText();
|
||||
enableCaptioningManager();
|
||||
} else if (mFontSize == preference) {
|
||||
Settings.Secure.putFloat(
|
||||
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
|
||||
Float.parseFloat((String) value));
|
||||
refreshPreviewText();
|
||||
enableCaptioningManager();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void enableCaptioningManager() {
|
||||
if (mCaptioningManager.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
Settings.Secure.putInt(getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, ON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHelpResource() {
|
||||
return R.string.help_url_caption;
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.view.accessibility.CaptioningManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
/** Controller that shows the caption scale and style summary. */
|
||||
public class CaptionAppearancePreferenceController extends BasePreferenceController {
|
||||
|
||||
private final CaptioningManager mCaptioningManager;
|
||||
|
||||
public CaptionAppearancePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mCaptioningManager = context.getSystemService(CaptioningManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return mContext.getString(R.string.preference_summary_default_combination,
|
||||
geFontScaleSummary(), getPresetSummary());
|
||||
}
|
||||
|
||||
private float[] getFontScaleValuesArray() {
|
||||
final String[] fontScaleValuesStrArray = mContext.getResources().getStringArray(
|
||||
R.array.captioning_font_size_selector_values);
|
||||
final int length = fontScaleValuesStrArray.length;
|
||||
final float[] fontScaleValuesArray = new float[length];
|
||||
for (int i = 0; i < length; ++i) {
|
||||
fontScaleValuesArray[i] = Float.parseFloat(fontScaleValuesStrArray[i]);
|
||||
}
|
||||
return fontScaleValuesArray;
|
||||
}
|
||||
|
||||
private CharSequence geFontScaleSummary() {
|
||||
final float[] fontScaleValuesArray = getFontScaleValuesArray();
|
||||
final String[] fontScaleSummaries = mContext.getResources().getStringArray(
|
||||
R.array.captioning_font_size_selector_titles);
|
||||
final float fontScale = mCaptioningManager.getFontScale();
|
||||
final int idx = Floats.indexOf(fontScaleValuesArray, fontScale);
|
||||
return fontScaleSummaries[idx == /* not exist */ -1 ? 0 : idx];
|
||||
}
|
||||
|
||||
private CharSequence getPresetSummary() {
|
||||
final int[] presetValuesArray = mContext.getResources().getIntArray(
|
||||
R.array.captioning_preset_selector_values);
|
||||
final String[] presetSummaries = mContext.getResources().getStringArray(
|
||||
R.array.captioning_preset_selector_titles);
|
||||
final int preset = mCaptioningManager.getRawUserStyle();
|
||||
final int idx = Ints.indexOf(presetValuesArray, preset);
|
||||
return presetSummaries[idx];
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ public class CaptionFooterPreferenceController extends AccessibilityFooterPrefer
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLearnMoreContentDescription() {
|
||||
protected String getLearnMoreText() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_captioning_footer_learn_more_content_description);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
||||
|
||||
import com.google.common.primitives.Floats;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -56,7 +54,6 @@ public class CaptionPropertiesFragment extends DashboardFragment
|
||||
private Preference mMoreOptions;
|
||||
|
||||
private final List<Preference> mPreferenceList = new ArrayList<>();
|
||||
private float[] mFontSizeValuesArray;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -71,13 +68,12 @@ public class CaptionPropertiesFragment extends DashboardFragment
|
||||
|
||||
initializeAllPreferences();
|
||||
installUpdateListeners();
|
||||
initFontSizeValuesArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateAllPreferences();
|
||||
mSwitch.setChecked(mCaptioningManager.isEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,21 +101,6 @@ public class CaptionPropertiesFragment extends DashboardFragment
|
||||
|
||||
}
|
||||
|
||||
private void initFontSizeValuesArray() {
|
||||
final String[] fontSizeValuesStrArray = getPrefContext().getResources().getStringArray(
|
||||
R.array.captioning_font_size_selector_values);
|
||||
final int length = fontSizeValuesStrArray.length;
|
||||
mFontSizeValuesArray = new float[length];
|
||||
for (int i = 0; i < length; ++i) {
|
||||
mFontSizeValuesArray[i] = Float.parseFloat(fontSizeValuesStrArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAllPreferences() {
|
||||
mSwitch.setChecked(mCaptioningManager.isEnabled());
|
||||
mTextAppearance.setSummary(geTextAppearanceSummary(getPrefContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object value) {
|
||||
final ContentResolver cr = getActivity().getContentResolver();
|
||||
@@ -136,16 +117,6 @@ public class CaptionPropertiesFragment extends DashboardFragment
|
||||
return R.string.help_url_caption;
|
||||
}
|
||||
|
||||
private CharSequence geTextAppearanceSummary(Context context) {
|
||||
final String[] fontSizeSummaries = context.getResources().getStringArray(
|
||||
R.array.captioning_font_size_selector_summaries);
|
||||
|
||||
final float fontSize = mCaptioningManager.getFontScale();
|
||||
final int idx = Floats.indexOf(mFontSizeValuesArray, fontSize);
|
||||
|
||||
return fontSizeSummaries[idx == /* not exist */ -1 ? 0 : idx];
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.captioning_settings);
|
||||
|
||||
|
||||
@@ -30,11 +30,11 @@ import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
/** Accessibility settings for text and display. */
|
||||
/** Accessibility settings for color and motion. */
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class TextAndDisplayFragment extends DashboardFragment {
|
||||
public class ColorAndMotionFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "TextAndDisplayFragment";
|
||||
private static final String TAG = "ColorAndMotionFragment";
|
||||
|
||||
private static final String CATEGORY_EXPERIMENTAL = "experimental_category";
|
||||
|
||||
@@ -49,7 +49,7 @@ public class TextAndDisplayFragment extends DashboardFragment {
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCESSIBILITY_TEXT_AND_DISPLAY;
|
||||
return SettingsEnums.ACCESSIBILITY_COLOR_AND_MOTION;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class TextAndDisplayFragment extends DashboardFragment {
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accessibility_text_and_display;
|
||||
return R.xml.accessibility_color_and_motion;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,5 +104,5 @@ public class TextAndDisplayFragment extends DashboardFragment {
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_text_and_display);
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_color_and_motion);
|
||||
}
|
||||
@@ -30,7 +30,7 @@ import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.widget.RadioButtonPreference;
|
||||
import com.android.settingslib.widget.SelectorWithWidgetPreference;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.Map;
|
||||
|
||||
/** Controller class that control radio button of accessibility daltonizer settings. */
|
||||
public class DaltonizerRadioButtonPreferenceController extends BasePreferenceController implements
|
||||
LifecycleObserver, RadioButtonPreference.OnClickListener {
|
||||
LifecycleObserver, SelectorWithWidgetPreference.OnClickListener {
|
||||
private static final String TYPE = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER;
|
||||
|
||||
// pair the preference key and daltonizer value.
|
||||
@@ -49,7 +49,7 @@ public class DaltonizerRadioButtonPreferenceController extends BasePreferenceCon
|
||||
private final ContentResolver mContentResolver;
|
||||
private final Resources mResources;
|
||||
private DaltonizerRadioButtonPreferenceController.OnChangeListener mOnChangeListener;
|
||||
private RadioButtonPreference mPreference;
|
||||
private SelectorWithWidgetPreference mPreference;
|
||||
private int mAccessibilityDaltonizerValue;
|
||||
|
||||
public DaltonizerRadioButtonPreferenceController(Context context, String preferenceKey) {
|
||||
@@ -120,7 +120,7 @@ public class DaltonizerRadioButtonPreferenceController extends BasePreferenceCon
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreference = (RadioButtonPreference)
|
||||
mPreference = (SelectorWithWidgetPreference)
|
||||
screen.findPreference(getPreferenceKey());
|
||||
mPreference.setOnClickListener(this);
|
||||
mPreference.setAppendixVisibility(View.GONE);
|
||||
@@ -128,7 +128,7 @@ public class DaltonizerRadioButtonPreferenceController extends BasePreferenceCon
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRadioButtonClicked(RadioButtonPreference preference) {
|
||||
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
|
||||
final int value = getDaltonizerValueToKeyMap().get(mPreferenceKey);
|
||||
handlePreferenceChange(String.valueOf(value));
|
||||
if (mOnChangeListener != null) {
|
||||
|
||||
65
src/com/android/settings/accessibility/DisplaySizeData.java
Normal file
65
src/com/android/settings/accessibility/DisplaySizeData.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.settingslib.display.DisplayDensityConfiguration;
|
||||
import com.android.settingslib.display.DisplayDensityUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Data class for storing the configurations related to the display size.
|
||||
*/
|
||||
class DisplaySizeData extends PreviewSizeData<Integer> {
|
||||
DisplaySizeData(Context context) {
|
||||
super(context);
|
||||
|
||||
final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
|
||||
final int initialIndex = density.getCurrentIndex();
|
||||
if (initialIndex < 0) {
|
||||
// Failed to obtain default density, which means we failed to
|
||||
// connect to the window manager service. Just use the current
|
||||
// density and don't let the user change anything.
|
||||
final Resources resources = getContext().getResources();
|
||||
final int densityDpi = resources.getDisplayMetrics().densityDpi;
|
||||
setDefaultValue(densityDpi);
|
||||
setInitialIndex(0);
|
||||
setValues(Collections.singletonList(densityDpi));
|
||||
} else {
|
||||
setDefaultValue(density.getDefaultDensity());
|
||||
setInitialIndex(initialIndex);
|
||||
setValues(Arrays.stream(density.getValues()).boxed().collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void commit(int currentProgress) {
|
||||
final int densityDpi = getValues().get(currentProgress);
|
||||
if (densityDpi == getDefaultValue()) {
|
||||
DisplayDensityConfiguration.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
|
||||
} else {
|
||||
DisplayDensityConfiguration.setForcedDisplayDensity(Display.DEFAULT_DISPLAY,
|
||||
densityDpi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,9 +51,7 @@ public class FloatingMenuTransparencyPreferenceController extends SliderPreferen
|
||||
private final ContentResolver mContentResolver;
|
||||
@VisibleForTesting
|
||||
final ContentObserver mContentObserver;
|
||||
|
||||
@VisibleForTesting
|
||||
SeekBarPreference mPreference;
|
||||
private SeekBarPreference mPreference;
|
||||
|
||||
public FloatingMenuTransparencyPreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
@@ -83,6 +81,7 @@ public class FloatingMenuTransparencyPreferenceController extends SliderPreferen
|
||||
mPreference.setMin(getMin());
|
||||
mPreference.setHapticFeedbackMode(SeekBarPreference.HAPTIC_FEEDBACK_MODE_ON_ENDS);
|
||||
|
||||
updateAvailabilityStatus();
|
||||
updateState(mPreference);
|
||||
}
|
||||
|
||||
|
||||
58
src/com/android/settings/accessibility/FontSizeData.java
Normal file
58
src/com/android/settings/accessibility/FontSizeData.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 static com.android.settings.display.ToggleFontSizePreferenceFragment.fontSizeValueToIndex;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Data class for storing the configurations related to the font size.
|
||||
*/
|
||||
final class FontSizeData extends PreviewSizeData<Float> {
|
||||
private static final float FONT_SCALE_DEF_VALUE = 1.0f;
|
||||
|
||||
FontSizeData(Context context) {
|
||||
super(context);
|
||||
|
||||
final Resources resources = getContext().getResources();
|
||||
final ContentResolver resolver = getContext().getContentResolver();
|
||||
final List<String> strEntryValues =
|
||||
Arrays.asList(resources.getStringArray(R.array.entryvalues_font_size));
|
||||
setDefaultValue(FONT_SCALE_DEF_VALUE);
|
||||
final float currentScale =
|
||||
Settings.System.getFloat(resolver, Settings.System.FONT_SCALE, getDefaultValue());
|
||||
setInitialIndex(fontSizeValueToIndex(currentScale, strEntryValues.toArray(new String[0])));
|
||||
setValues(strEntryValues.stream().map(Float::valueOf).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
void commit(int currentProgress) {
|
||||
final ContentResolver resolver = getContext().getContentResolver();
|
||||
Settings.System.putFloat(resolver, Settings.System.FONT_SCALE,
|
||||
getValues().get(currentProgress));
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.VISION_FRAGMENT_NO;
|
||||
import static com.android.settings.core.SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.FragmentType;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
|
||||
|
||||
/** PreferenceController for displaying font size page. */
|
||||
public class FontSizePreferenceController extends BasePreferenceController {
|
||||
|
||||
public FontSizePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!mPreferenceKey.equals(preference.getKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(mContext,
|
||||
AccessibilityScreenSizeForSetupWizardActivity.class);
|
||||
intent.putExtra(VISION_FRAGMENT_NO, FragmentType.FONT_SIZE);
|
||||
intent.putExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_FADE);
|
||||
mContext.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,19 @@ import android.graphics.fonts.FontStyle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.core.instrumentation.SettingsStatsLog;
|
||||
|
||||
/** PreferenceController for displaying all text in bold. */
|
||||
public class FontWeightAdjustmentPreferenceController extends TogglePreferenceController {
|
||||
public class FontWeightAdjustmentPreferenceController extends TogglePreferenceController implements
|
||||
TextReadingResetController.ResetStateListener {
|
||||
static final int BOLD_TEXT_ADJUSTMENT =
|
||||
FontStyle.FONT_WEIGHT_BOLD - FontStyle.FONT_WEIGHT_NORMAL;
|
||||
|
||||
@EntryPoint
|
||||
private int mEntryPoint;
|
||||
|
||||
public FontWeightAdjustmentPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
@@ -45,6 +51,12 @@ public class FontWeightAdjustmentPreferenceController extends TogglePreferenceCo
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
SettingsStatsLog.write(
|
||||
SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED,
|
||||
AccessibilityStatsLogUtils.convertToItemKeyName(getPreferenceKey()),
|
||||
isChecked ? 1 : 0,
|
||||
AccessibilityStatsLogUtils.convertToEntryPoint(mEntryPoint));
|
||||
|
||||
return Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.FONT_WEIGHT_ADJUSTMENT, (isChecked ? BOLD_TEXT_ADJUSTMENT : 0));
|
||||
}
|
||||
@@ -53,4 +65,18 @@ public class FontWeightAdjustmentPreferenceController extends TogglePreferenceCo
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
setChecked(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point is used for logging.
|
||||
*
|
||||
* @param entryPoint from which settings page
|
||||
*/
|
||||
void setEntryPoint(@EntryPoint int entryPoint) {
|
||||
mEntryPoint = entryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,30 +16,72 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/** Preference controller for haptic feedback intensity */
|
||||
public class HapticFeedbackIntensityPreferenceController
|
||||
extends VibrationIntensityPreferenceController {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String PREF_KEY = "touch_vibration_preference_screen";
|
||||
/** General configuration for haptic feedback intensity settings. */
|
||||
public static final class HapticFeedbackVibrationPreferenceConfig
|
||||
extends VibrationPreferenceConfig {
|
||||
|
||||
public HapticFeedbackIntensityPreferenceController(Context context) {
|
||||
super(context, PREF_KEY, Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
Settings.System.HAPTIC_FEEDBACK_ENABLED);
|
||||
public HapticFeedbackVibrationPreferenceConfig(Context context) {
|
||||
super(context, Settings.System.HAPTIC_FEEDBACK_INTENSITY,
|
||||
VibrationAttributes.USAGE_TOUCH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readIntensity() {
|
||||
final int hapticFeedbackEnabled = Settings.System.getInt(mContentResolver,
|
||||
Settings.System.HAPTIC_FEEDBACK_ENABLED, ON);
|
||||
|
||||
if (hapticFeedbackEnabled == OFF) {
|
||||
// HAPTIC_FEEDBACK_ENABLED is deprecated but should still be applied if the user has
|
||||
// turned it off already.
|
||||
return Vibrator.VIBRATION_INTENSITY_OFF;
|
||||
}
|
||||
|
||||
return super.readIntensity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateIntensity(int intensity) {
|
||||
final boolean success = super.updateIntensity(intensity);
|
||||
final boolean isIntensityOff = intensity == Vibrator.VIBRATION_INTENSITY_OFF;
|
||||
|
||||
Settings.System.putInt(mContentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED,
|
||||
isIntensityOff ? OFF : ON);
|
||||
// HAPTIC_FEEDBACK_ENABLED is deprecated but should still reflect the intensity setting.
|
||||
|
||||
// HARDWARE_HAPTIC_FEEDBACK_INTENSITY is dependent on this setting, but should not be
|
||||
// disabled by it.
|
||||
Settings.System.putInt(mContentResolver,
|
||||
Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY,
|
||||
isIntensityOff ? getDefaultIntensity() : intensity);
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
public HapticFeedbackIntensityPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new HapticFeedbackVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
protected HapticFeedbackIntensityPreferenceController(Context context, String preferenceKey,
|
||||
int supportedIntensityLevels) {
|
||||
super(context, preferenceKey, new HapticFeedbackVibrationPreferenceConfig(context),
|
||||
supportedIntensityLevels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultIntensity() {
|
||||
return mVibrator.getDefaultHapticFeedbackIntensity();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
|
||||
import com.android.settings.accessibility.HapticFeedbackIntensityPreferenceController.HapticFeedbackVibrationPreferenceConfig;
|
||||
|
||||
/** Preference controller for haptic feedback with only a toggle for on/off states. */
|
||||
public class HapticFeedbackTogglePreferenceController extends VibrationTogglePreferenceController {
|
||||
|
||||
public HapticFeedbackTogglePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new HapticFeedbackVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package com.android.settings.accessibility;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -30,24 +29,17 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
|
||||
public class HearingAidDialogFragment extends InstrumentedDialogFragment {
|
||||
public static HearingAidDialogFragment newInstance() {
|
||||
HearingAidDialogFragment frag = new HearingAidDialogFragment();
|
||||
return frag;
|
||||
return new HearingAidDialogFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.accessibility_hearingaid_pair_instructions_title)
|
||||
.setMessage(R.string.accessibility_hearingaid_pair_instructions_message)
|
||||
.setPositiveButton(R.string.accessibility_hearingaid_instruction_continue_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
launchBluetoothAddDeviceSetting();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) { }
|
||||
})
|
||||
(dialog, which) -> launchBluetoothAddDeviceSetting())
|
||||
.setNegativeButton(android.R.string.cancel, /* listener= */ null)
|
||||
.create();
|
||||
}
|
||||
|
||||
|
||||
59
src/com/android/settings/accessibility/HearingAidUtils.java
Normal file
59
src/com/android/settings/accessibility/HearingAidUtils.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.settings.bluetooth.HearingAidPairingDialogFragment;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.HearingAidProfile;
|
||||
|
||||
/** Provides utility methods related hearing aids. */
|
||||
public final class HearingAidUtils {
|
||||
private static final String TAG = "HearingAidUtils";
|
||||
|
||||
private HearingAidUtils(){}
|
||||
|
||||
/**
|
||||
* Launches pairing dialog when hearing aid device needs other side of hearing aid device to
|
||||
* work.
|
||||
*
|
||||
* @param fragmentManager The {@link FragmentManager} used to show dialog fragment
|
||||
* @param device The {@link CachedBluetoothDevice} need to be hearing aid device
|
||||
*/
|
||||
public static void launchHearingAidPairingDialog(FragmentManager fragmentManager,
|
||||
@NonNull CachedBluetoothDevice device) {
|
||||
if (device.isConnectedHearingAidDevice()
|
||||
&& device.getDeviceMode() == HearingAidProfile.DeviceMode.MODE_BINAURAL
|
||||
&& device.getSubDevice() == null) {
|
||||
launchHearingAidPairingDialogInternal(fragmentManager, device);
|
||||
}
|
||||
}
|
||||
|
||||
private static void launchHearingAidPairingDialogInternal(FragmentManager fragmentManager,
|
||||
@NonNull CachedBluetoothDevice device) {
|
||||
if (device.getDeviceSide() == HearingAidProfile.DeviceSide.SIDE_INVALID) {
|
||||
Log.w(TAG, "Can not launch hearing aid pairing dialog for invalid side");
|
||||
return;
|
||||
}
|
||||
HearingAidPairingDialogFragment.newInstance(device).show(fragmentManager,
|
||||
HearingAidPairingDialogFragment.TAG);
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,23 @@ package com.android.settings.accessibility;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
public class HighTextContrastPreferenceController extends TogglePreferenceController {
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.core.instrumentation.SettingsStatsLog;
|
||||
|
||||
/**
|
||||
* PreferenceController for displaying all text in high contrast style.
|
||||
*/
|
||||
public class HighTextContrastPreferenceController extends TogglePreferenceController implements
|
||||
TextReadingResetController.ResetStateListener {
|
||||
private SwitchPreference mSwitchPreference;
|
||||
|
||||
@EntryPoint
|
||||
private int mEntryPoint;
|
||||
|
||||
public HighTextContrastPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
@@ -41,6 +54,12 @@ public class HighTextContrastPreferenceController extends TogglePreferenceContro
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
SettingsStatsLog.write(
|
||||
SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED,
|
||||
AccessibilityStatsLogUtils.convertToItemKeyName(getPreferenceKey()),
|
||||
isChecked ? 1 : 0,
|
||||
AccessibilityStatsLogUtils.convertToEntryPoint(mEntryPoint));
|
||||
|
||||
return Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, (isChecked ? 1 : 0));
|
||||
}
|
||||
@@ -49,4 +68,25 @@ public class HighTextContrastPreferenceController extends TogglePreferenceContro
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mSwitchPreference = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
setChecked(false);
|
||||
updateState(mSwitchPreference);
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point is used for logging.
|
||||
*
|
||||
* @param entryPoint from which settings page
|
||||
*/
|
||||
void setEntryPoint(@EntryPoint int entryPoint) {
|
||||
mEntryPoint = entryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -51,6 +52,7 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
private static final String TAG = "LaunchA11yActivity";
|
||||
private static final String EMPTY_STRING = "";
|
||||
protected static final String KEY_LAUNCH_PREFERENCE = "launch_preference";
|
||||
private ComponentName mTileComponentName;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -106,6 +108,13 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
AccessibilitySettings.EXTRA_SETTINGS_TITLE);
|
||||
mSettingsIntent = TextUtils.isEmpty(settingsTitle) ? null : getSettingsIntent(arguments);
|
||||
mSettingsTitle = (mSettingsIntent == null) ? null : settingsTitle;
|
||||
|
||||
// Tile service.
|
||||
if (arguments.containsKey(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME)) {
|
||||
final String tileServiceComponentName = arguments.getString(
|
||||
AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME);
|
||||
mTileComponentName = ComponentName.unflattenFromString(tileServiceComponentName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,6 +123,29 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
||||
mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
ComponentName getTileComponentName() {
|
||||
return mTileComponentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
|
||||
final ComponentName componentName = getTileComponentName();
|
||||
if (componentName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CharSequence tileName = loadTileLabel(getPrefContext(), componentName);
|
||||
if (tileName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int titleResId = type == QuickSettingsTooltipType.GUIDE_TO_EDIT
|
||||
? R.string.accessibility_service_qs_tooltip_content
|
||||
: R.string.accessibility_service_auto_added_qs_tooltip_content;
|
||||
return getString(titleResId, tileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
// Do not call super. We don't want to see the "Help & feedback" option on this page so as
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.android.internal.view.RotationPolicy;
|
||||
import com.android.internal.view.RotationPolicy.RotationPolicyListener;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.display.DeviceStateAutoRotationHelper;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
@@ -59,7 +60,9 @@ public class LockScreenRotationPreferenceController extends TogglePreferenceCont
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return RotationPolicy.isRotationSupported(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
return RotationPolicy.isRotationSupported(mContext)
|
||||
&& !DeviceStateAutoRotationHelper.isDeviceStateRotationEnabledForA11y(mContext)
|
||||
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** Controller that accesses and switches the preference status of following typing feature */
|
||||
public class MagnificationFollowTypingPreferenceController extends TogglePreferenceController
|
||||
implements LifecycleObserver {
|
||||
|
||||
private static final String TAG =
|
||||
MagnificationFollowTypingPreferenceController.class.getSimpleName();
|
||||
static final String PREF_KEY = "magnification_follow_typing";
|
||||
|
||||
private SwitchPreference mFollowTypingPreference;
|
||||
|
||||
public MagnificationFollowTypingPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, ON) == ON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
return Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED,
|
||||
(isChecked ? ON : OFF));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return R.string.menu_key_accessibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mFollowTypingPreference = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
// TODO(b/186731461): Remove it when this controller is used in DashBoardFragment only.
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
void onResume() {
|
||||
updateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the state of preference components which has been displayed by
|
||||
* {@link MagnificationFollowTypingPreferenceController#displayPreference}.
|
||||
*/
|
||||
void updateState() {
|
||||
updateState(mFollowTypingPreference);
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,10 @@ public class MagnificationGesturesPreferenceController extends TogglePreferenceC
|
||||
extras.putInt(AccessibilitySettings.EXTRA_TITLE_RES,
|
||||
R.string.accessibility_screen_magnification_gestures_title);
|
||||
|
||||
String summary = context.getString(R.string.accessibility_screen_magnification_summary);
|
||||
String intro = context.getString(R.string.accessibility_screen_magnification_intro_text);
|
||||
extras.putCharSequence(AccessibilitySettings.EXTRA_INTRO, intro);
|
||||
|
||||
String summary = context.getString(R.string.accessibility_screen_magnification_summary);
|
||||
final Object[] numberArguments = {1, 2, 3, 4, 5};
|
||||
summary = MessageFormat.format(summary, numberArguments);
|
||||
extras.putCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, summary);
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
|
||||
import static com.android.settings.accessibility.AccessibilityDialogUtils.CustomButton;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
@@ -27,12 +25,13 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -45,6 +44,7 @@ import com.android.settings.DialogCreatable;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.utils.AnnotationSpan;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnCreate;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
@@ -52,7 +52,6 @@ import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/** Controller that shows the magnification area mode summary and the preference click behavior. */
|
||||
public class MagnificationModePreferenceController extends BasePreferenceController implements
|
||||
@@ -63,17 +62,18 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
@VisibleForTesting
|
||||
static final int DIALOG_MAGNIFICATION_MODE = DIALOG_ID_BASE + 1;
|
||||
@VisibleForTesting
|
||||
static final int DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = DIALOG_ID_BASE + 2;
|
||||
static final int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = DIALOG_ID_BASE + 2;
|
||||
@VisibleForTesting
|
||||
static final String EXTRA_MODE = "mode";
|
||||
|
||||
private static final String TAG = "MagnificationModePreferenceController";
|
||||
private static final char COMPONENT_NAME_SEPARATOR = ':';
|
||||
|
||||
private DialogHelper mDialogHelper;
|
||||
// The magnification mode in the dialog.
|
||||
private int mMode = MagnificationMode.NONE;
|
||||
@MagnificationMode
|
||||
private int mModeCache = MagnificationMode.NONE;
|
||||
private Preference mModePreference;
|
||||
private ShortcutPreference mLinkPreference;
|
||||
|
||||
@VisibleForTesting
|
||||
ListView mMagnificationModesListView;
|
||||
@@ -113,7 +113,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (savedInstanceState != null) {
|
||||
mMode = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
|
||||
mModeCache = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +121,10 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mModePreference = screen.findPreference(getPreferenceKey());
|
||||
mLinkPreference = screen.findPreference(
|
||||
ToggleFeaturePreferenceFragment.KEY_SHORTCUT_PREFERENCE);
|
||||
mModePreference.setOnPreferenceClickListener(preference -> {
|
||||
mMode = MagnificationCapabilities.getCapabilities(mContext);
|
||||
mModeCache = MagnificationCapabilities.getCapabilities(mContext);
|
||||
mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
|
||||
return true;
|
||||
});
|
||||
@@ -130,7 +132,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt(EXTRA_MODE, mMode);
|
||||
outState.putInt(EXTRA_MODE, mModeCache);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,8 +149,8 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
case DIALOG_MAGNIFICATION_MODE:
|
||||
return createMagnificationModeDialog();
|
||||
|
||||
case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
|
||||
return createMagnificationShortCutConfirmDialog();
|
||||
case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
|
||||
return createMagnificationTripleTapWarningDialog();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -158,8 +160,8 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
switch (dialogId) {
|
||||
case DIALOG_MAGNIFICATION_MODE:
|
||||
return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
|
||||
case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
|
||||
return SettingsEnums.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT;
|
||||
case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
|
||||
return SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -178,29 +180,40 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
mMagnificationModesListView.setItemChecked(computeSelectionIndex(), true);
|
||||
final CharSequence title = mContext.getString(
|
||||
R.string.accessibility_magnification_mode_dialog_title);
|
||||
final CharSequence positiveBtnText = mContext.getString(R.string.save);
|
||||
final CharSequence negativeBtnText = mContext.getString(R.string.cancel);
|
||||
|
||||
return AccessibilityDialogUtils.createCustomDialog(mContext, title,
|
||||
mMagnificationModesListView, this::onMagnificationModeDialogPositiveButtonClicked);
|
||||
mMagnificationModesListView,
|
||||
positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked,
|
||||
negativeBtnText, /* negativeListener= */ null);
|
||||
}
|
||||
|
||||
private void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
|
||||
@VisibleForTesting
|
||||
void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
|
||||
int which) {
|
||||
final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition();
|
||||
if (selectedIndex != AdapterView.INVALID_POSITION) {
|
||||
final MagnificationModeInfo modeInfo =
|
||||
(MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
|
||||
selectedIndex);
|
||||
setMode(modeInfo.mMagnificationMode);
|
||||
} else {
|
||||
if (selectedIndex == AdapterView.INVALID_POSITION) {
|
||||
Log.w(TAG, "invalid index");
|
||||
return;
|
||||
}
|
||||
|
||||
mModeCache = ((MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
|
||||
selectedIndex)).mMagnificationMode;
|
||||
|
||||
// Do not save mode until user clicks positive button in triple tap warning dialog.
|
||||
if (isTripleTapEnabled(mContext) && mModeCache != MagnificationMode.FULLSCREEN) {
|
||||
mDialogHelper.showDialog(DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
|
||||
} else { // Save mode (capabilities) value, don't need to show dialog to confirm.
|
||||
updateCapabilitiesAndSummary(mModeCache);
|
||||
}
|
||||
}
|
||||
|
||||
private void setMode(int mode) {
|
||||
mMode = mode;
|
||||
MagnificationCapabilities.setCapabilities(mContext, mMode);
|
||||
private void updateCapabilitiesAndSummary(@MagnificationMode int mode) {
|
||||
mModeCache = mode;
|
||||
MagnificationCapabilities.setCapabilities(mContext, mModeCache);
|
||||
mModePreference.setSummary(
|
||||
MagnificationCapabilities.getSummary(mContext, mMode));
|
||||
MagnificationCapabilities.getSummary(mContext, mModeCache));
|
||||
}
|
||||
|
||||
private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position,
|
||||
@@ -208,19 +221,16 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
final MagnificationModeInfo modeInfo =
|
||||
(MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
|
||||
position);
|
||||
if (modeInfo.mMagnificationMode == mMode) {
|
||||
if (modeInfo.mMagnificationMode == mModeCache) {
|
||||
return;
|
||||
}
|
||||
mMode = modeInfo.mMagnificationMode;
|
||||
if (isTripleTapEnabled(mContext) && mMode != MagnificationMode.FULLSCREEN) {
|
||||
mDialogHelper.showDialog(DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
|
||||
}
|
||||
mModeCache = modeInfo.mMagnificationMode;
|
||||
}
|
||||
|
||||
private int computeSelectionIndex() {
|
||||
final int modesSize = mModeInfos.size();
|
||||
for (int i = 0; i < modesSize; i++) {
|
||||
if (mModeInfos.get(i).mMagnificationMode == mMode) {
|
||||
if (mModeInfos.get(i).mMagnificationMode == mModeCache) {
|
||||
return i + mMagnificationModesListView.getHeaderViewsCount();
|
||||
}
|
||||
}
|
||||
@@ -234,41 +244,57 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
|
||||
}
|
||||
|
||||
private Dialog createMagnificationShortCutConfirmDialog() {
|
||||
return AccessibilityDialogUtils.createMagnificationSwitchShortcutDialog(mContext,
|
||||
this::onSwitchShortcutDialogButtonClicked);
|
||||
private Dialog createMagnificationTripleTapWarningDialog() {
|
||||
final View contentView = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.magnification_triple_tap_warning_dialog, /* root= */ null);
|
||||
final CharSequence title = mContext.getString(
|
||||
R.string.accessibility_magnification_triple_tap_warning_title);
|
||||
final CharSequence positiveBtnText = mContext.getString(
|
||||
R.string.accessibility_magnification_triple_tap_warning_positive_button);
|
||||
final CharSequence negativeBtnText = mContext.getString(
|
||||
R.string.accessibility_magnification_triple_tap_warning_negative_button);
|
||||
|
||||
final Dialog dialog = AccessibilityDialogUtils.createCustomDialog(mContext, title,
|
||||
contentView,
|
||||
positiveBtnText, this::onMagnificationTripleTapWarningDialogPositiveButtonClicked,
|
||||
negativeBtnText, this::onMagnificationTripleTapWarningDialogNegativeButtonClicked);
|
||||
|
||||
updateLinkInTripleTapWarningDialog(dialog, contentView);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private void updateLinkInTripleTapWarningDialog(Dialog dialog, View contentView) {
|
||||
final TextView messageView = contentView.findViewById(R.id.message);
|
||||
// TODO(b/225682559): Need to remove performClick() after refactoring accessibility dialog.
|
||||
final View.OnClickListener linkListener = view -> {
|
||||
updateCapabilitiesAndSummary(mModeCache);
|
||||
mLinkPreference.performClick();
|
||||
dialog.dismiss();
|
||||
};
|
||||
final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
|
||||
AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, linkListener);
|
||||
final CharSequence textWithLink = AnnotationSpan.linkify(mContext.getText(
|
||||
R.string.accessibility_magnification_triple_tap_warning_message), linkInfo);
|
||||
|
||||
if (messageView != null) {
|
||||
messageView.setText(textWithLink);
|
||||
messageView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
dialog.setContentView(contentView);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onSwitchShortcutDialogButtonClicked(@CustomButton int which) {
|
||||
optOutMagnificationFromTripleTap();
|
||||
//TODO(b/147990389): Merge this function into AccessibilityUtils after the format of
|
||||
// magnification target is changed to ComponentName.
|
||||
optInMagnificationToAccessibilityButton();
|
||||
void onMagnificationTripleTapWarningDialogNegativeButtonClicked(
|
||||
DialogInterface dialogInterface, int which) {
|
||||
mModeCache = MagnificationCapabilities.getCapabilities(mContext);
|
||||
mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
|
||||
}
|
||||
|
||||
private void optOutMagnificationFromTripleTap() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF);
|
||||
}
|
||||
|
||||
private void optInMagnificationToAccessibilityButton() {
|
||||
final String targetKey = Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
|
||||
final String targetString = Settings.Secure.getString(mContext.getContentResolver(),
|
||||
targetKey);
|
||||
if (targetString != null && targetString.contains(MAGNIFICATION_CONTROLLER_NAME)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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(mContext.getContentResolver(), targetKey,
|
||||
joiner.toString());
|
||||
@VisibleForTesting
|
||||
void onMagnificationTripleTapWarningDialogPositiveButtonClicked(
|
||||
DialogInterface dialogInterface, int which) {
|
||||
updateCapabilitiesAndSummary(mModeCache);
|
||||
}
|
||||
|
||||
// TODO(b/186731461): Remove it when this controller is used in DashBoardFragment only.
|
||||
@@ -277,7 +303,6 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
|
||||
updateState(mModePreference);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An interface to help the delegate to show the dialog. It will be injected to the delegate.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.provider.Settings;
|
||||
|
||||
/** Preference controller for am vibration intensity */
|
||||
public class MediaVibrationIntensityPreferenceController
|
||||
extends VibrationIntensityPreferenceController {
|
||||
|
||||
/** General configuration for alarm vibration intensity settings. */
|
||||
public static final class MediaVibrationPreferenceConfig extends VibrationPreferenceConfig {
|
||||
|
||||
public MediaVibrationPreferenceConfig(Context context) {
|
||||
super(context, Settings.System.MEDIA_VIBRATION_INTENSITY,
|
||||
VibrationAttributes.USAGE_MEDIA);
|
||||
}
|
||||
}
|
||||
|
||||
public MediaVibrationIntensityPreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
super(context, preferenceKey, new MediaVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
protected MediaVibrationIntensityPreferenceController(Context context, String preferenceKey,
|
||||
int supportedIntensityLevels) {
|
||||
super(context, preferenceKey, new MediaVibrationPreferenceConfig(context),
|
||||
supportedIntensityLevels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
|
||||
import com.android.settings.accessibility.MediaVibrationIntensityPreferenceController.MediaVibrationPreferenceConfig;
|
||||
|
||||
/** Preference controller for alarm vibration with only a toggle for on/off states. */
|
||||
public class MediaVibrationTogglePreferenceController extends VibrationTogglePreferenceController {
|
||||
|
||||
public MediaVibrationTogglePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new MediaVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -17,27 +17,42 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/** Preference controller for notification vibration intensity */
|
||||
public class NotificationVibrationIntensityPreferenceController
|
||||
extends VibrationIntensityPreferenceController {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String PREF_KEY = "notification_vibration_preference_screen";
|
||||
/** General configuration for notification vibration intensity settings. */
|
||||
public static final class NotificationVibrationPreferenceConfig
|
||||
extends VibrationPreferenceConfig {
|
||||
|
||||
public NotificationVibrationIntensityPreferenceController(Context context) {
|
||||
super(context, PREF_KEY, Settings.System.NOTIFICATION_VIBRATION_INTENSITY, "");
|
||||
public NotificationVibrationPreferenceConfig(Context context) {
|
||||
super(context, Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
|
||||
VibrationAttributes.USAGE_NOTIFICATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRestrictedByRingerModeSilent() {
|
||||
// Notifications never vibrate when the phone is in silent mode.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public NotificationVibrationIntensityPreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
super(context, preferenceKey, new NotificationVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
protected NotificationVibrationIntensityPreferenceController(Context context,
|
||||
String preferenceKey, int supportedIntensityLevels) {
|
||||
super(context, preferenceKey, new NotificationVibrationPreferenceConfig(context),
|
||||
supportedIntensityLevels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultIntensity() {
|
||||
return mVibrator.getDefaultNotificationVibrationIntensity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.media.AudioAttributes;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* Fragment for picking accessibility shortcut service
|
||||
*/
|
||||
public class NotificationVibrationPreferenceFragment extends VibrationPreferenceFragment {
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCESSIBILITY_VIBRATION_NOTIFICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accessibility_notification_vibration_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the setting string of the vibration intensity setting this preference is dealing with.
|
||||
*/
|
||||
@Override
|
||||
protected String getVibrationIntensitySetting() {
|
||||
return Settings.System.NOTIFICATION_VIBRATION_INTENSITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getVibrationEnabledSetting() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreviewVibrationAudioAttributesUsage() {
|
||||
return AudioAttributes.USAGE_NOTIFICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultVibrationIntensity() {
|
||||
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
|
||||
return vibrator.getDefaultNotificationVibrationIntensity();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
|
||||
import com.android.settings.accessibility.NotificationVibrationIntensityPreferenceController.NotificationVibrationPreferenceConfig;
|
||||
|
||||
/** Preference controller for notification vibration with only a toggle for on/off states. */
|
||||
public class NotificationVibrationTogglePreferenceController
|
||||
extends VibrationTogglePreferenceController {
|
||||
|
||||
public NotificationVibrationTogglePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new NotificationVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -148,6 +148,8 @@ public final class PaletteListPreference extends Preference {
|
||||
|
||||
rootView.addView(textView);
|
||||
}
|
||||
|
||||
updateFirstAndLastItemsBackground(context, rootView, paletteData.size());
|
||||
}
|
||||
|
||||
private GradientDrawable createGradientDrawable(ViewGroup rootView, @ColorInt int color) {
|
||||
@@ -164,6 +166,19 @@ public final class PaletteListPreference extends Preference {
|
||||
return gradientDrawable;
|
||||
}
|
||||
|
||||
private void updateFirstAndLastItemsBackground(Context context, ViewGroup rootView, int size) {
|
||||
final int radius =
|
||||
context.getResources().getDimensionPixelSize(
|
||||
R.dimen.accessibility_illustration_view_radius);
|
||||
final int lastIndex = size - 1;
|
||||
final GradientDrawable firstItem =
|
||||
(GradientDrawable) rootView.getChildAt(0).getBackground();
|
||||
final GradientDrawable lastItem =
|
||||
(GradientDrawable) rootView.getChildAt(lastIndex).getBackground();
|
||||
firstItem.setCornerRadii(new float[]{radius, radius, radius, radius, 0, 0, 0, 0});
|
||||
lastItem.setCornerRadii(new float[]{0, 0, 0, 0, radius, radius, radius, radius});
|
||||
}
|
||||
|
||||
private List<Integer> getPaletteColors(Context context) {
|
||||
final int[] paletteResources =
|
||||
context.getResources().getIntArray(R.array.setting_palette_colors);
|
||||
|
||||
71
src/com/android/settings/accessibility/PreviewSizeData.java
Normal file
71
src/com/android/settings/accessibility/PreviewSizeData.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract data class for storing and fetching the configurations related to the preview of the
|
||||
* text and reading options.
|
||||
*/
|
||||
abstract class PreviewSizeData<T extends Number> {
|
||||
private final Context mContext;
|
||||
private int mInitialIndex;
|
||||
private T mDefaultValue;
|
||||
private List<T> mValues;
|
||||
|
||||
PreviewSizeData(@NonNull Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
List<T> getValues() {
|
||||
return mValues;
|
||||
}
|
||||
|
||||
void setValues(List<T> values) {
|
||||
mValues = values;
|
||||
}
|
||||
|
||||
T getDefaultValue() {
|
||||
return mDefaultValue;
|
||||
}
|
||||
|
||||
void setDefaultValue(T defaultValue) {
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
int getInitialIndex() {
|
||||
return mInitialIndex;
|
||||
}
|
||||
|
||||
void setInitialIndex(int initialIndex) {
|
||||
mInitialIndex = initialIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the selected size.
|
||||
*/
|
||||
abstract void commit(int currentProgress);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.widget.LabeledSeekBarPreference;
|
||||
|
||||
/**
|
||||
* The controller of {@link LabeledSeekBarPreference} that listens to display size and font size
|
||||
* settings changes and updates preview size threshold smoothly.
|
||||
*/
|
||||
class PreviewSizeSeekBarController extends BasePreferenceController implements
|
||||
TextReadingResetController.ResetStateListener {
|
||||
private final PreviewSizeData<? extends Number> mSizeData;
|
||||
private boolean mSeekByTouch;
|
||||
private ProgressInteractionListener mInteractionListener;
|
||||
private LabeledSeekBarPreference mSeekBarPreference;
|
||||
|
||||
private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
|
||||
new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
mInteractionListener.notifyPreferenceChanged();
|
||||
|
||||
if (!mSeekByTouch && mInteractionListener != null) {
|
||||
mInteractionListener.onProgressChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
mSeekByTouch = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
mSeekByTouch = false;
|
||||
|
||||
if (mInteractionListener != null) {
|
||||
mInteractionListener.onEndTrackingTouch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PreviewSizeSeekBarController(Context context, String preferenceKey,
|
||||
@NonNull PreviewSizeData<? extends Number> sizeData) {
|
||||
super(context, preferenceKey);
|
||||
mSizeData = sizeData;
|
||||
}
|
||||
|
||||
void setInteractionListener(ProgressInteractionListener interactionListener) {
|
||||
mInteractionListener = interactionListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
final int dataSize = mSizeData.getValues().size();
|
||||
final int initialIndex = mSizeData.getInitialIndex();
|
||||
mSeekBarPreference = screen.findPreference(getPreferenceKey());
|
||||
mSeekBarPreference.setMax(dataSize - 1);
|
||||
mSeekBarPreference.setProgress(initialIndex);
|
||||
mSeekBarPreference.setContinuousUpdates(true);
|
||||
mSeekBarPreference.setOnSeekBarChangeListener(mSeekBarChangeListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
final int defaultProgress = mSizeData.getValues().indexOf(mSizeData.getDefaultValue());
|
||||
mSeekBarPreference.setProgress(defaultProgress);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface for callbacks when users interact with the seek bar.
|
||||
*/
|
||||
interface ProgressInteractionListener {
|
||||
|
||||
/**
|
||||
* Called when the progress is changed.
|
||||
*/
|
||||
void notifyPreferenceChanged();
|
||||
|
||||
/**
|
||||
* Called when the progress is changed without tracking touch.
|
||||
*/
|
||||
void onProgressChanged();
|
||||
|
||||
/**
|
||||
* Called when the seek bar is end tracking.
|
||||
*/
|
||||
void onEndTrackingTouch();
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
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;
|
||||
@@ -30,14 +33,14 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.widget.PrimarySwitchPreference;
|
||||
import com.android.settingslib.PrimarySwitchPreference;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
|
||||
/** PreferenceController that shows the Reduce Bright Colors summary */
|
||||
public class ReduceBrightColorsPreferenceController extends TogglePreferenceController
|
||||
public class ReduceBrightColorsPreferenceController
|
||||
extends AccessibilityQuickSettingsPrimarySwitchPreferenceController
|
||||
implements LifecycleObserver, OnStart, OnStop {
|
||||
private ContentObserver mSettingsContentObserver;
|
||||
private PrimarySwitchPreference mPreference;
|
||||
@@ -67,6 +70,7 @@ public class ReduceBrightColorsPreferenceController extends TogglePreferenceCont
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
super.setChecked(isChecked);
|
||||
return mColorDisplayManager.setReduceBrightColorsActivated(isChecked);
|
||||
}
|
||||
|
||||
@@ -105,8 +109,20 @@ public class ReduceBrightColorsPreferenceController extends TogglePreferenceCont
|
||||
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
|
||||
false, mSettingsContentObserver, UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mSettingsContentObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentName getTileComponentName() {
|
||||
return 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,339 @@
|
||||
/*
|
||||
* 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 static com.android.settingslib.widget.TwoTargetPreference.ICON_SIZE_MEDIUM;
|
||||
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.accessibilityservice.AccessibilityShortcutInfo;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class helps setup RestrictedPreference for accessibility.
|
||||
*/
|
||||
public class RestrictedPreferenceHelper {
|
||||
// Index of the first preference in a preference category.
|
||||
private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1;
|
||||
|
||||
private final Context mContext;
|
||||
private final DevicePolicyManager mDpm;
|
||||
private final PackageManager mPm;
|
||||
private final AppOpsManager mAppOps;
|
||||
|
||||
public RestrictedPreferenceHelper(Context context) {
|
||||
mContext = context;
|
||||
mDpm = context.getSystemService(DevicePolicyManager.class);
|
||||
mPm = context.getPackageManager();
|
||||
mAppOps = context.getSystemService(AppOpsManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the list of {@link RestrictedPreference} with the installedServices arguments.
|
||||
*
|
||||
* @param installedServices The list of {@link AccessibilityServiceInfo}s of the
|
||||
* installed accessibility services
|
||||
* @return The list of {@link RestrictedPreference}
|
||||
*/
|
||||
public List<RestrictedPreference> createAccessibilityServicePreferenceList(
|
||||
List<AccessibilityServiceInfo> installedServices) {
|
||||
|
||||
final Set<ComponentName> enabledServices =
|
||||
AccessibilityUtils.getEnabledServicesFromSettings(mContext);
|
||||
final List<String> permittedServices = mDpm.getPermittedAccessibilityServices(
|
||||
UserHandle.myUserId());
|
||||
final int installedServicesSize = installedServices.size();
|
||||
|
||||
final List<RestrictedPreference> preferenceList = new ArrayList<>(
|
||||
installedServicesSize);
|
||||
|
||||
for (int i = 0; i < installedServicesSize; ++i) {
|
||||
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 String key = componentName.flattenToString();
|
||||
final CharSequence title = resolveInfo.loadLabel(mPm);
|
||||
final boolean serviceEnabled = enabledServices.contains(componentName);
|
||||
final CharSequence summary = AccessibilitySettings.getServiceSummary(
|
||||
mContext, info, serviceEnabled);
|
||||
final String fragment = getAccessibilityServiceFragmentTypeName(info);
|
||||
|
||||
Drawable icon = resolveInfo.loadIcon(mPm);
|
||||
if (resolveInfo.getIconResource() == 0) {
|
||||
icon = ContextCompat.getDrawable(mContext,
|
||||
R.drawable.ic_accessibility_generic);
|
||||
}
|
||||
|
||||
final RestrictedPreference preference = createRestrictedPreference(key, title,
|
||||
summary, icon, fragment, packageName,
|
||||
resolveInfo.serviceInfo.applicationInfo.uid);
|
||||
|
||||
setRestrictedPreferenceEnabled(preference, permittedServices, serviceEnabled);
|
||||
|
||||
final String prefKey = preference.getKey();
|
||||
final int imageRes = info.getAnimatedImageRes();
|
||||
final CharSequence intro = info.loadIntro(mPm);
|
||||
final CharSequence description = AccessibilitySettings.getServiceDescription(
|
||||
mContext, info, serviceEnabled);
|
||||
final String htmlDescription = info.loadHtmlDescription(mPm);
|
||||
final String settingsClassName = info.getSettingsActivityName();
|
||||
final String tileServiceClassName = info.getTileServiceName();
|
||||
|
||||
putBasicExtras(preference, prefKey, title, intro, description, imageRes,
|
||||
htmlDescription, componentName);
|
||||
putServiceExtras(preference, resolveInfo, serviceEnabled);
|
||||
putSettingsExtras(preference, packageName, settingsClassName);
|
||||
putTileServiceExtras(preference, packageName, tileServiceClassName);
|
||||
|
||||
preferenceList.add(preference);
|
||||
}
|
||||
return preferenceList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the list of {@link RestrictedPreference} with the installedShortcuts arguments.
|
||||
*
|
||||
* @param installedShortcuts The list of {@link AccessibilityShortcutInfo}s of the
|
||||
* installed accessibility shortcuts
|
||||
* @return The list of {@link RestrictedPreference}
|
||||
*/
|
||||
public List<RestrictedPreference> 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<RestrictedPreference> preferenceList = new ArrayList<>(
|
||||
installedShortcutsSize);
|
||||
|
||||
for (int i = 0; i < installedShortcutsSize; ++i) {
|
||||
final AccessibilityShortcutInfo info = installedShortcuts.get(i);
|
||||
final ActivityInfo activityInfo = info.getActivityInfo();
|
||||
final ComponentName componentName = info.getComponentName();
|
||||
|
||||
final String key = componentName.flattenToString();
|
||||
final CharSequence title = activityInfo.loadLabel(mPm);
|
||||
final String summary = info.loadSummary(mPm);
|
||||
final String fragment =
|
||||
LaunchAccessibilityActivityPreferenceFragment.class.getName();
|
||||
|
||||
Drawable icon = activityInfo.loadIcon(mPm);
|
||||
if (activityInfo.getIconResource() == 0) {
|
||||
icon = ContextCompat.getDrawable(mContext, R.drawable.ic_accessibility_generic);
|
||||
}
|
||||
|
||||
final RestrictedPreference preference = createRestrictedPreference(key, title,
|
||||
summary, icon, fragment, componentName.getPackageName(),
|
||||
activityInfo.applicationInfo.uid);
|
||||
final boolean serviceEnabled = enabledServices.contains(componentName);
|
||||
|
||||
setRestrictedPreferenceEnabled(preference, permittedServices, serviceEnabled);
|
||||
|
||||
final String prefKey = preference.getKey();
|
||||
final CharSequence intro = info.loadIntro(mPm);
|
||||
final String description = info.loadDescription(mPm);
|
||||
final int imageRes = info.getAnimatedImageRes();
|
||||
final String htmlDescription = info.loadHtmlDescription(mPm);
|
||||
final String settingsClassName = info.getSettingsActivityName();
|
||||
final String tileServiceClassName = info.getTileServiceName();
|
||||
|
||||
putBasicExtras(preference, prefKey, title, intro, description, imageRes,
|
||||
htmlDescription, componentName);
|
||||
putSettingsExtras(preference, componentName.getPackageName(), settingsClassName);
|
||||
putTileServiceExtras(preference, componentName.getPackageName(),
|
||||
tileServiceClassName);
|
||||
|
||||
preferenceList.add(preference);
|
||||
}
|
||||
return preferenceList;
|
||||
}
|
||||
|
||||
private String getAccessibilityServiceFragmentTypeName(AccessibilityServiceInfo info) {
|
||||
final int type = AccessibilityUtil.getAccessibilityServiceFragmentType(info);
|
||||
switch (type) {
|
||||
case AccessibilityUtil.AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE:
|
||||
return VolumeShortcutToggleAccessibilityServicePreferenceFragment.class.getName();
|
||||
case AccessibilityUtil.AccessibilityServiceFragmentType.INVISIBLE_TOGGLE:
|
||||
return InvisibleToggleAccessibilityServicePreferenceFragment.class.getName();
|
||||
case AccessibilityUtil.AccessibilityServiceFragmentType.TOGGLE:
|
||||
return ToggleAccessibilityServicePreferenceFragment.class.getName();
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported accessibility fragment type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private RestrictedPreference createRestrictedPreference(String key, CharSequence title,
|
||||
CharSequence summary, Drawable icon, String fragment, String packageName, int uid) {
|
||||
final RestrictedPreference preference = new RestrictedPreference(mContext, packageName,
|
||||
uid);
|
||||
|
||||
preference.setKey(key);
|
||||
preference.setTitle(title);
|
||||
preference.setSummary(summary);
|
||||
preference.setIcon(Utils.getAdaptiveIcon(mContext, icon, Color.WHITE));
|
||||
preference.setFragment(fragment);
|
||||
preference.setIconSize(ICON_SIZE_MEDIUM);
|
||||
preference.setPersistent(false); // Disable SharedPreferences.
|
||||
preference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
|
||||
|
||||
return preference;
|
||||
}
|
||||
|
||||
private void setRestrictedPreferenceEnabled(RestrictedPreference preference,
|
||||
final List<String> permittedServices, boolean serviceEnabled) {
|
||||
// permittedServices null means all accessibility services are allowed.
|
||||
boolean serviceAllowed = permittedServices == null || permittedServices.contains(
|
||||
preference.getPackageName());
|
||||
boolean appOpsAllowed;
|
||||
if (serviceAllowed) {
|
||||
try {
|
||||
final int mode = mAppOps.noteOpNoThrow(
|
||||
AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
|
||||
preference.getUid(), preference.getPackageName());
|
||||
final boolean ecmEnabled = mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
|
||||
appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
|
||||
serviceAllowed = appOpsAllowed;
|
||||
} catch (Exception e) {
|
||||
// Allow service in case if app ops is not available in testing.
|
||||
appOpsAllowed = true;
|
||||
}
|
||||
} else {
|
||||
appOpsAllowed = false;
|
||||
}
|
||||
if (serviceAllowed || serviceEnabled) {
|
||||
preference.setEnabled(true);
|
||||
} else {
|
||||
// Disable accessibility service that are not permitted.
|
||||
final RestrictedLockUtils.EnforcedAdmin admin =
|
||||
RestrictedLockUtilsInternal.checkIfAccessibilityServiceDisallowed(
|
||||
mContext, preference.getPackageName(), UserHandle.myUserId());
|
||||
|
||||
if (admin != null) {
|
||||
preference.setDisabledByAdmin(admin);
|
||||
} else if (!appOpsAllowed) {
|
||||
preference.setDisabledByAppOps(true);
|
||||
} else {
|
||||
preference.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Puts the basic extras into {@link RestrictedPreference}'s getExtras(). */
|
||||
private void putBasicExtras(RestrictedPreference preference, String prefKey,
|
||||
CharSequence title, CharSequence intro, CharSequence summary, int imageRes,
|
||||
String htmlDescription, ComponentName componentName) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
extras.putString(AccessibilitySettings.EXTRA_PREFERENCE_KEY, prefKey);
|
||||
extras.putCharSequence(AccessibilitySettings.EXTRA_TITLE, title);
|
||||
extras.putCharSequence(AccessibilitySettings.EXTRA_INTRO, intro);
|
||||
extras.putCharSequence(AccessibilitySettings.EXTRA_SUMMARY, summary);
|
||||
extras.putParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME, componentName);
|
||||
extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, imageRes);
|
||||
extras.putString(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, htmlDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the service extras into {@link RestrictedPreference}'s getExtras().
|
||||
*
|
||||
* <p><b>Note:</b> Called by {@link AccessibilityServiceInfo}.</p>
|
||||
*
|
||||
* @param preference The preference we are configuring.
|
||||
* @param resolveInfo The service resolve info.
|
||||
* @param serviceEnabled Whether the accessibility service is enabled.
|
||||
*/
|
||||
private void putServiceExtras(RestrictedPreference preference, ResolveInfo resolveInfo,
|
||||
Boolean serviceEnabled) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
|
||||
extras.putParcelable(AccessibilitySettings.EXTRA_RESOLVE_INFO, resolveInfo);
|
||||
extras.putBoolean(AccessibilitySettings.EXTRA_CHECKED, serviceEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the settings extras into {@link RestrictedPreference}'s getExtras().
|
||||
*
|
||||
* <p><b>Note:</b> Called when settings UI is needed.</p>
|
||||
*
|
||||
* @param preference The preference we are configuring.
|
||||
* @param packageName Package of accessibility feature.
|
||||
* @param settingsClassName The component name of an activity that allows the user to modify
|
||||
* the settings for this accessibility feature.
|
||||
*/
|
||||
private void putSettingsExtras(RestrictedPreference preference, String packageName,
|
||||
String settingsClassName) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
|
||||
if (!TextUtils.isEmpty(settingsClassName)) {
|
||||
extras.putString(AccessibilitySettings.EXTRA_SETTINGS_TITLE,
|
||||
mContext.getText(R.string.accessibility_menu_item_settings).toString());
|
||||
extras.putString(AccessibilitySettings.EXTRA_SETTINGS_COMPONENT_NAME,
|
||||
new ComponentName(packageName, settingsClassName).flattenToString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the information about a particular application
|
||||
* {@link android.service.quicksettings.TileService} into {@link RestrictedPreference}'s
|
||||
* getExtras().
|
||||
*
|
||||
* <p><b>Note:</b> Called when a tooltip of
|
||||
* {@link android.service.quicksettings.TileService} is needed.</p>
|
||||
*
|
||||
* @param preference The preference we are configuring.
|
||||
* @param packageName Package of accessibility feature.
|
||||
* @param tileServiceClassName The component name of tileService is associated with this
|
||||
* accessibility feature.
|
||||
*/
|
||||
private void putTileServiceExtras(RestrictedPreference preference, String packageName,
|
||||
String tileServiceClassName) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
if (!TextUtils.isEmpty(tileServiceClassName)) {
|
||||
extras.putString(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME,
|
||||
new ComponentName(packageName, tileServiceClassName).flattenToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,28 +17,23 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/** Preference controller for ringtone vibration intensity */
|
||||
public class RingVibrationIntensityPreferenceController
|
||||
extends VibrationIntensityPreferenceController {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String PREF_KEY = "ring_vibration_preference_screen";
|
||||
public RingVibrationIntensityPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new RingVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
public RingVibrationIntensityPreferenceController(Context context) {
|
||||
super(context, PREF_KEY, Settings.System.RING_VIBRATION_INTENSITY,
|
||||
Settings.System.VIBRATE_WHEN_RINGING, /* supportRampingRinger= */ true);
|
||||
protected RingVibrationIntensityPreferenceController(Context context, String preferenceKey,
|
||||
int supportedIntensityLevels) {
|
||||
super(context, preferenceKey, new RingVibrationPreferenceConfig(context),
|
||||
supportedIntensityLevels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultIntensity() {
|
||||
return mVibrator.getDefaultRingVibrationIntensity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
|
||||
/** General configuration for ringtone vibration intensity settings. */
|
||||
public class RingVibrationPreferenceConfig extends VibrationPreferenceConfig {
|
||||
private final AudioManager mAudioManager;
|
||||
|
||||
public RingVibrationPreferenceConfig(Context context) {
|
||||
super(context, Settings.System.RING_VIBRATION_INTENSITY,
|
||||
VibrationAttributes.USAGE_RINGTONE);
|
||||
mAudioManager = context.getSystemService(AudioManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRestrictedByRingerModeSilent() {
|
||||
// Incoming calls never vibrate when the phone is in silent mode.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateIntensity(int intensity) {
|
||||
final boolean success = super.updateIntensity(intensity);
|
||||
|
||||
// VIBRATE_WHEN_RINGING is deprecated but should still reflect the intensity setting.
|
||||
// Ramping ringer is independent of the ring intensity and should not be affected.
|
||||
Settings.System.putInt(mContentResolver, Settings.System.VIBRATE_WHEN_RINGING,
|
||||
(intensity == Vibrator.VIBRATION_INTENSITY_OFF) ? OFF : ON);
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.media.AudioAttributes;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* Fragment for picking accessibility shortcut service
|
||||
*/
|
||||
public class RingVibrationPreferenceFragment extends VibrationPreferenceFragment {
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCESSIBILITY_VIBRATION_RING;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accessibility_ring_vibration_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the setting string of the vibration intensity setting this preference is dealing with.
|
||||
*/
|
||||
@Override
|
||||
protected String getVibrationIntensitySetting() {
|
||||
return Settings.System.RING_VIBRATION_INTENSITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getVibrationEnabledSetting() {
|
||||
if (AccessibilitySettings.isRampingRingerEnabled(getContext())) {
|
||||
return Settings.Global.APPLY_RAMPING_RINGER;
|
||||
} else {
|
||||
return Settings.System.VIBRATE_WHEN_RINGING;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreviewVibrationAudioAttributesUsage() {
|
||||
return AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultVibrationIntensity() {
|
||||
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
|
||||
return vibrator.getDefaultRingVibrationIntensity();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
|
||||
/** Preference controller for ringtone vibration with only a toggle for on/off states. */
|
||||
public class RingVibrationTogglePreferenceController extends VibrationTogglePreferenceController {
|
||||
|
||||
public RingVibrationTogglePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey, new RingVibrationPreferenceConfig(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.VISION_FRAGMENT_NO;
|
||||
import static com.android.settings.core.SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.accessibility.AccessibilityScreenSizeForSetupWizardActivity.FragmentType;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
|
||||
|
||||
/** PreferenceController for displaying screen size page. */
|
||||
public class ScreenSizePreferenceController extends BasePreferenceController {
|
||||
|
||||
public ScreenSizePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!mPreferenceKey.equals(preference.getKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(mContext,
|
||||
AccessibilityScreenSizeForSetupWizardActivity.class);
|
||||
intent.putExtra(VISION_FRAGMENT_NO, FragmentType.SCREEN_SIZE);
|
||||
intent.putExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_FADE);
|
||||
mContext.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.ContentResolver;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
abstract class SettingsContentObserver extends ContentObserver {
|
||||
private final List<String> mKeysToObserve = new ArrayList<>(2);
|
||||
|
||||
public SettingsContentObserver(Handler handler) {
|
||||
super(handler);
|
||||
mKeysToObserve.add(Settings.Secure.ACCESSIBILITY_ENABLED);
|
||||
mKeysToObserve.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
|
||||
}
|
||||
|
||||
public SettingsContentObserver(Handler handler, List<String> keysToObserve) {
|
||||
this(handler);
|
||||
mKeysToObserve.addAll(keysToObserve);
|
||||
}
|
||||
|
||||
public void register(ContentResolver contentResolver) {
|
||||
for (int i = 0; i < mKeysToObserve.size(); i++) {
|
||||
contentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(mKeysToObserve.get(i)), false, this);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregister(ContentResolver contentResolver) {
|
||||
contentResolver.unregisterContentObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void onChange(boolean selfChange, Uri uri);
|
||||
}
|
||||
@@ -64,6 +64,11 @@ public class ShortcutPreference extends Preference {
|
||||
setLayoutResource(R.layout.accessibility_shortcut_secondary_action);
|
||||
setWidgetLayoutResource(R.layout.preference_widget_primary_switch);
|
||||
setIconSpaceReserved(false);
|
||||
// Treat onSettingsClicked as this preference's click.
|
||||
setOnPreferenceClickListener(preference -> {
|
||||
callOnSettingsClicked();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 static com.android.settings.accessibility.TextReadingPreferenceFragment.EXTRA_LAUNCHED_FROM;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/**
|
||||
* The base controller for the fragment{@link TextReadingPreferenceFragment}.
|
||||
*/
|
||||
public class TextReadingFragmentBaseController extends BasePreferenceController {
|
||||
@EntryPoint
|
||||
private int mEntryPoint;
|
||||
|
||||
private TextReadingFragmentBaseController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
TextReadingFragmentBaseController(Context context, String preferenceKey,
|
||||
@EntryPoint int entryPoint) {
|
||||
this(context, preferenceKey);
|
||||
mEntryPoint = entryPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (getPreferenceKey().equals(preference.getKey())) {
|
||||
final Bundle extras = preference.getExtras();
|
||||
extras.putInt(EXTRA_LAUNCHED_FROM, mEntryPoint);
|
||||
}
|
||||
|
||||
return super.handlePreferenceTreeClick(preference);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 static com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint.ACCESSIBILITY_SETTINGS;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* The controller for the {@link TextReadingPreferenceFragment} from the accessibility settings.
|
||||
*/
|
||||
public class TextReadingFragmentForA11ySettingsController extends
|
||||
TextReadingFragmentBaseController {
|
||||
public TextReadingFragmentForA11ySettingsController(Context context, String preferenceKey) {
|
||||
// Pass the fixed entry point to the parent controller for logging.
|
||||
super(context, preferenceKey, ACCESSIBILITY_SETTINGS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 static com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint.DISPLAY_SETTINGS;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* The controller for the {@link TextReadingPreferenceFragment} from the display settings.
|
||||
*/
|
||||
public class TextReadingFragmentForDisplaySettingsController extends
|
||||
TextReadingFragmentBaseController {
|
||||
public TextReadingFragmentForDisplaySettingsController(Context context, String preferenceKey) {
|
||||
// Pass the fixed entry point to the parent controller for logging.
|
||||
super(context, preferenceKey, DISPLAY_SETTINGS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 static com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint.SUW_VISION_SETTINGS;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* The controller for the {@link TextReadingPreferenceFragment} during the SetupWizard.
|
||||
*/
|
||||
public class TextReadingFragmentForSuwController extends TextReadingFragmentBaseController {
|
||||
public TextReadingFragmentForSuwController(Context context, String preferenceKey) {
|
||||
// Pass the fixed entry point to the parent controller for logging.
|
||||
super(context, preferenceKey, SUW_VISION_SETTINGS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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 static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Accessibility settings for adjusting the system features which are related to the reading. For
|
||||
* example, bold text, high contrast text, display size, font size and so on.
|
||||
*/
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class TextReadingPreferenceFragment extends DashboardFragment {
|
||||
public static final String EXTRA_LAUNCHED_FROM = "launched_from";
|
||||
private static final String TAG = "TextReadingPreferenceFragment";
|
||||
private static final String CATEGORY_FOR_ANYTHING_ELSE =
|
||||
"com.android.settings.suggested.category.DISPLAY_SETTINGS";
|
||||
static final String FONT_SIZE_KEY = "font_size";
|
||||
static final String DISPLAY_SIZE_KEY = "display_size";
|
||||
static final String BOLD_TEXT_KEY = "toggle_force_bold_text";
|
||||
static final String HIGH_TEXT_CONTRAST_KEY = "toggle_high_text_contrast_preference";
|
||||
static final String RESET_KEY = "reset";
|
||||
private static final String PREVIEW_KEY = "preview";
|
||||
private static final String NEED_RESET_SETTINGS = "need_reset_settings";
|
||||
private FontWeightAdjustmentPreferenceController mFontWeightAdjustmentController;
|
||||
private int mEntryPoint = EntryPoint.UNKNOWN_ENTRY;
|
||||
|
||||
/**
|
||||
* The entry point which launches the {@link TextReadingPreferenceFragment}.
|
||||
*
|
||||
* <p>This should only be used for logging.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
EntryPoint.UNKNOWN_ENTRY,
|
||||
EntryPoint.SUW_VISION_SETTINGS,
|
||||
EntryPoint.SUW_ANYTHING_ELSE,
|
||||
EntryPoint.DISPLAY_SETTINGS,
|
||||
EntryPoint.ACCESSIBILITY_SETTINGS,
|
||||
})
|
||||
@interface EntryPoint {
|
||||
int UNKNOWN_ENTRY = 0;
|
||||
int SUW_VISION_SETTINGS = 1;
|
||||
int SUW_ANYTHING_ELSE = 2;
|
||||
int DISPLAY_SETTINGS = 3;
|
||||
int ACCESSIBILITY_SETTINGS = 4;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<ResetStateListener> mResetStateListeners;
|
||||
|
||||
@VisibleForTesting
|
||||
boolean mNeedResetSettings;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
mNeedResetSettings = false;
|
||||
mResetStateListeners = getResetStateListeners();
|
||||
|
||||
if (icicle != null && icicle.getBoolean(NEED_RESET_SETTINGS)) {
|
||||
mResetStateListeners.forEach(ResetStateListener::resetState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.accessibility_text_reading_options;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.ACCESSIBILITY_TEXT_READING_OPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
updateEntryPoint();
|
||||
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
final FontSizeData fontSizeData = new FontSizeData(context);
|
||||
final DisplaySizeData displaySizeData = createDisplaySizeData(context);
|
||||
|
||||
final TextReadingPreviewController previewController = new TextReadingPreviewController(
|
||||
context, PREVIEW_KEY, fontSizeData, displaySizeData);
|
||||
previewController.setEntryPoint(mEntryPoint);
|
||||
controllers.add(previewController);
|
||||
|
||||
final PreviewSizeSeekBarController fontSizeController = new PreviewSizeSeekBarController(
|
||||
context, FONT_SIZE_KEY, fontSizeData);
|
||||
fontSizeController.setInteractionListener(previewController);
|
||||
controllers.add(fontSizeController);
|
||||
|
||||
final PreviewSizeSeekBarController displaySizeController = new PreviewSizeSeekBarController(
|
||||
context, DISPLAY_SIZE_KEY, displaySizeData);
|
||||
displaySizeController.setInteractionListener(previewController);
|
||||
controllers.add(displaySizeController);
|
||||
|
||||
mFontWeightAdjustmentController =
|
||||
new FontWeightAdjustmentPreferenceController(context, BOLD_TEXT_KEY);
|
||||
mFontWeightAdjustmentController.setEntryPoint(mEntryPoint);
|
||||
controllers.add(mFontWeightAdjustmentController);
|
||||
|
||||
final HighTextContrastPreferenceController highTextContrastController =
|
||||
new HighTextContrastPreferenceController(context, HIGH_TEXT_CONTRAST_KEY);
|
||||
highTextContrastController.setEntryPoint(mEntryPoint);
|
||||
controllers.add(highTextContrastController);
|
||||
|
||||
final TextReadingResetController resetController =
|
||||
new TextReadingResetController(context, RESET_KEY,
|
||||
v -> showDialog(DialogEnums.DIALOG_RESET_SETTINGS));
|
||||
resetController.setEntryPoint(mEntryPoint);
|
||||
controllers.add(resetController);
|
||||
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(int dialogId) {
|
||||
if (dialogId == DialogEnums.DIALOG_RESET_SETTINGS) {
|
||||
return new AlertDialog.Builder(getPrefContext())
|
||||
.setTitle(R.string.accessibility_text_reading_confirm_dialog_title)
|
||||
.setMessage(R.string.accessibility_text_reading_confirm_dialog_message)
|
||||
.setPositiveButton(
|
||||
R.string.accessibility_text_reading_confirm_dialog_reset_button,
|
||||
this::onPositiveButtonClicked)
|
||||
.setNegativeButton(R.string.cancel, /* listener= */ null)
|
||||
.create();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDialogMetricsCategory(int dialogId) {
|
||||
if (dialogId == DialogEnums.DIALOG_RESET_SETTINGS) {
|
||||
return SettingsEnums.DIALOG_RESET_SETTINGS;
|
||||
}
|
||||
|
||||
return super.getDialogMetricsCategory(dialogId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
if (mNeedResetSettings) {
|
||||
outState.putBoolean(NEED_RESET_SETTINGS, true);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
DisplaySizeData createDisplaySizeData(Context context) {
|
||||
return new DisplaySizeData(context);
|
||||
}
|
||||
|
||||
private void updateEntryPoint() {
|
||||
final Bundle bundle = getArguments();
|
||||
if (bundle != null && bundle.containsKey(EXTRA_LAUNCHED_FROM)) {
|
||||
mEntryPoint = bundle.getInt(EXTRA_LAUNCHED_FROM, EntryPoint.UNKNOWN_ENTRY);
|
||||
return;
|
||||
}
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null) {
|
||||
mEntryPoint = EntryPoint.UNKNOWN_ENTRY;
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<String> categories = intent.getCategories();
|
||||
mEntryPoint = categories != null && categories.contains(CATEGORY_FOR_ANYTHING_ELSE)
|
||||
? EntryPoint.SUW_ANYTHING_ELSE : EntryPoint.UNKNOWN_ENTRY;
|
||||
}
|
||||
|
||||
private void onPositiveButtonClicked(DialogInterface dialog, int which) {
|
||||
// To avoid showing the dialog again, probably the onDetach() of SettingsDialogFragment
|
||||
// was interrupted by unexpectedly recreating the activity.
|
||||
removeDialog(DialogEnums.DIALOG_RESET_SETTINGS);
|
||||
|
||||
if (mFontWeightAdjustmentController.isChecked()) {
|
||||
// TODO(b/228956791): Consider replacing or removing it once the root cause is
|
||||
// clarified and the better method is available.
|
||||
// Probably has the race condition issue between "Bold text" and the other features
|
||||
// including "Display Size", “Font Size” if they would be enabled at the same time,
|
||||
// so our workaround is that the “Bold text” would be reset first and then do the
|
||||
// remaining to avoid flickering problem.
|
||||
mNeedResetSettings = true;
|
||||
mFontWeightAdjustmentController.resetState();
|
||||
} else {
|
||||
mResetStateListeners.forEach(ResetStateListener::resetState);
|
||||
}
|
||||
|
||||
Toast.makeText(getPrefContext(), R.string.accessibility_text_reading_reset_message,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private List<ResetStateListener> getResetStateListeners() {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
getPreferenceControllers().forEach(controllers::addAll);
|
||||
return controllers.stream().filter(c -> c instanceof ResetStateListener).map(
|
||||
c -> (ResetStateListener) c).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.accessibility_text_reading_options);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.app.settings.SettingsEnums;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
import com.google.android.setupdesign.util.LayoutStyler;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link androidx.preference.PreferenceFragmentCompat} that displays the settings page related
|
||||
* to the text and reading option in the SetupWizard.
|
||||
*/
|
||||
public class TextReadingPreferenceFragmentForSetupWizard extends TextReadingPreferenceFragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
|
||||
final String title = getContext().getString(
|
||||
R.string.accessibility_text_reading_options_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);
|
||||
|
||||
updateResetButtonPadding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
|
||||
Bundle savedInstanceState) {
|
||||
final GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
|
||||
return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.SUW_ACCESSIBILITY_TEXT_READING_OPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHelpResource() {
|
||||
// Hides help center in action bar and footer bar in SuW
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the padding of the reset button to meet for SetupWizard style.
|
||||
*/
|
||||
private void updateResetButtonPadding() {
|
||||
final LayoutPreference resetPreference = (LayoutPreference) findPreference(RESET_KEY);
|
||||
final ViewGroup parentView =
|
||||
(ViewGroup) resetPreference.findViewById(R.id.reset_button).getParent();
|
||||
LayoutStyler.applyPartnerCustomizationLayoutPaddingStyle(parentView);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.Choreographer;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.instrumentation.SettingsStatsLog;
|
||||
import com.android.settings.display.PreviewPagerAdapter;
|
||||
import com.android.settings.widget.LabeledSeekBarPreference;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link BasePreferenceController} for controlling the preview pager of the text and reading
|
||||
* options.
|
||||
*/
|
||||
class TextReadingPreviewController extends BasePreferenceController implements
|
||||
PreviewSizeSeekBarController.ProgressInteractionListener {
|
||||
private static final String TAG = "TextReadingPreviewCtrl";
|
||||
static final int[] PREVIEW_SAMPLE_RES_IDS = new int[]{
|
||||
R.layout.accessibility_text_reading_preview_app_grid,
|
||||
R.layout.screen_zoom_preview_1,
|
||||
R.layout.accessibility_text_reading_preview_mail_content};
|
||||
|
||||
private static final String PREVIEW_KEY = "preview";
|
||||
private static final String FONT_SIZE_KEY = "font_size";
|
||||
private static final String DISPLAY_SIZE_KEY = "display_size";
|
||||
private static final long MIN_COMMIT_INTERVAL_MS = 800;
|
||||
private static final long CHANGE_BY_SEEKBAR_DELAY_MS = 100;
|
||||
private static final long CHANGE_BY_BUTTON_DELAY_MS = 300;
|
||||
private final FontSizeData mFontSizeData;
|
||||
private final DisplaySizeData mDisplaySizeData;
|
||||
private int mLastFontProgress;
|
||||
private int mLastDisplayProgress;
|
||||
private long mLastCommitTime;
|
||||
private TextReadingPreviewPreference mPreviewPreference;
|
||||
private LabeledSeekBarPreference mFontSizePreference;
|
||||
private LabeledSeekBarPreference mDisplaySizePreference;
|
||||
|
||||
@EntryPoint
|
||||
private int mEntryPoint;
|
||||
|
||||
private final Choreographer.FrameCallback mCommit = f -> {
|
||||
tryCommitFontSizeConfig();
|
||||
tryCommitDisplaySizeConfig();
|
||||
|
||||
mLastCommitTime = SystemClock.elapsedRealtime();
|
||||
};
|
||||
|
||||
TextReadingPreviewController(Context context, String preferenceKey,
|
||||
@NonNull FontSizeData fontSizeData, @NonNull DisplaySizeData displaySizeData) {
|
||||
super(context, preferenceKey);
|
||||
mFontSizeData = fontSizeData;
|
||||
mDisplaySizeData = displaySizeData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mPreviewPreference = screen.findPreference(PREVIEW_KEY);
|
||||
|
||||
mFontSizePreference = screen.findPreference(FONT_SIZE_KEY);
|
||||
mDisplaySizePreference = screen.findPreference(DISPLAY_SIZE_KEY);
|
||||
Objects.requireNonNull(mFontSizePreference,
|
||||
/* message= */ "Font size preference is null, the preview controller "
|
||||
+ "couldn't get the info");
|
||||
Objects.requireNonNull(mDisplaySizePreference,
|
||||
/* message= */ "Display size preference is null, the preview controller"
|
||||
+ " couldn't get the info");
|
||||
|
||||
mLastFontProgress = mFontSizeData.getInitialIndex();
|
||||
mLastDisplayProgress = mDisplaySizeData.getInitialIndex();
|
||||
|
||||
final Configuration origConfig = mContext.getResources().getConfiguration();
|
||||
final boolean isLayoutRtl =
|
||||
origConfig.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
|
||||
final PreviewPagerAdapter pagerAdapter = new PreviewPagerAdapter(mContext, isLayoutRtl,
|
||||
PREVIEW_SAMPLE_RES_IDS, createConfig(origConfig));
|
||||
mPreviewPreference.setPreviewAdapter(pagerAdapter);
|
||||
pagerAdapter.setPreviewLayer(/* newLayerIndex= */ 0,
|
||||
/* currentLayerIndex= */ 0,
|
||||
/* currentFrameIndex= */ 0, /* animate= */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPreferenceChanged() {
|
||||
final int displayDataSize = mDisplaySizeData.getValues().size();
|
||||
final int fontSizeProgress = mFontSizePreference.getProgress();
|
||||
final int displaySizeProgress = mDisplaySizePreference.getProgress();
|
||||
|
||||
// To be consistent with the
|
||||
// {@link PreviewPagerAdapter#setPreviewLayer(int, int, int, boolean)} behavior,
|
||||
// here also needs the same design. In addition, please also refer to
|
||||
// the {@link #createConfig(Configuration)}.
|
||||
final int pagerIndex = fontSizeProgress * displayDataSize + displaySizeProgress;
|
||||
|
||||
mPreviewPreference.notifyPreviewPagerChanged(pagerIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged() {
|
||||
postCommitDelayed(CHANGE_BY_BUTTON_DELAY_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEndTrackingTouch() {
|
||||
postCommitDelayed(CHANGE_BY_SEEKBAR_DELAY_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point is used for logging.
|
||||
*
|
||||
* @param entryPoint from which settings page
|
||||
*/
|
||||
void setEntryPoint(@EntryPoint int entryPoint) {
|
||||
mEntryPoint = entryPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoids the flicker when switching to the previous or next level.
|
||||
*
|
||||
* <p><br>[Flickering problem steps] commit()-> snapshot in framework(old screenshot) ->
|
||||
* app update the preview -> snapshot(old screen) fade out</p>
|
||||
*
|
||||
* <p><br>To prevent flickering problem, we make sure that we update the local preview
|
||||
* first and then we do the commit later. </p>
|
||||
*
|
||||
* <p><br><b>Note:</b> It doesn't matter that we use
|
||||
* Choreographer or main thread handler since the delay time is longer
|
||||
* than 1 frame. Use Choreographer to let developer understand it's a
|
||||
* window update.</p>
|
||||
*
|
||||
* @param commitDelayMs the interval time after a action.
|
||||
*/
|
||||
void postCommitDelayed(long commitDelayMs) {
|
||||
if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
|
||||
commitDelayMs += MIN_COMMIT_INTERVAL_MS;
|
||||
}
|
||||
|
||||
final Choreographer choreographer = Choreographer.getInstance();
|
||||
choreographer.removeFrameCallback(mCommit);
|
||||
choreographer.postFrameCallbackDelayed(mCommit, commitDelayMs);
|
||||
}
|
||||
|
||||
private void tryCommitFontSizeConfig() {
|
||||
final int fontProgress = mFontSizePreference.getProgress();
|
||||
if (fontProgress != mLastFontProgress) {
|
||||
mFontSizeData.commit(fontProgress);
|
||||
mLastFontProgress = fontProgress;
|
||||
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Font size: " + fontProgress);
|
||||
}
|
||||
|
||||
SettingsStatsLog.write(
|
||||
SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED,
|
||||
AccessibilityStatsLogUtils.convertToItemKeyName(mFontSizePreference.getKey()),
|
||||
fontProgress,
|
||||
AccessibilityStatsLogUtils.convertToEntryPoint(mEntryPoint));
|
||||
}
|
||||
}
|
||||
|
||||
private void tryCommitDisplaySizeConfig() {
|
||||
final int displayProgress = mDisplaySizePreference.getProgress();
|
||||
if (displayProgress != mLastDisplayProgress) {
|
||||
mDisplaySizeData.commit(displayProgress);
|
||||
mLastDisplayProgress = displayProgress;
|
||||
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Display size: " + displayProgress);
|
||||
}
|
||||
|
||||
SettingsStatsLog.write(
|
||||
SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED,
|
||||
AccessibilityStatsLogUtils.convertToItemKeyName(
|
||||
mDisplaySizePreference.getKey()),
|
||||
displayProgress,
|
||||
AccessibilityStatsLogUtils.convertToEntryPoint(mEntryPoint));
|
||||
}
|
||||
}
|
||||
|
||||
private Configuration[] createConfig(Configuration origConfig) {
|
||||
final int fontDataSize = mFontSizeData.getValues().size();
|
||||
final int displayDataSize = mDisplaySizeData.getValues().size();
|
||||
final int totalNum = fontDataSize * displayDataSize;
|
||||
final Configuration[] configurations = new Configuration[totalNum];
|
||||
|
||||
for (int i = 0; i < fontDataSize; ++i) {
|
||||
for (int j = 0; j < displayDataSize; ++j) {
|
||||
final Configuration config = new Configuration(origConfig);
|
||||
config.fontScale = mFontSizeData.getValues().get(i);
|
||||
config.densityDpi = mDisplaySizeData.getValues().get(j);
|
||||
|
||||
configurations[i * displayDataSize + j] = config;
|
||||
}
|
||||
}
|
||||
|
||||
return configurations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.display.PreviewPagerAdapter;
|
||||
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 int mCurrentItem;
|
||||
private int mLastLayerIndex;
|
||||
private PreviewPagerAdapter mPreviewAdapter;
|
||||
|
||||
TextReadingPreviewPreference(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public TextReadingPreviewPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
TextReadingPreviewPreference(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
|
||||
final ViewPager viewPager = (ViewPager) holder.findViewById(R.id.preview_pager);
|
||||
final DotsPageIndicator pageIndicator =
|
||||
(DotsPageIndicator) holder.findViewById(R.id.page_indicator);
|
||||
updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter);
|
||||
updatePagerAndIndicator(viewPager, pageIndicator);
|
||||
}
|
||||
|
||||
void setPreviewAdapter(PreviewPagerAdapter previewAdapter) {
|
||||
if (previewAdapter != mPreviewAdapter) {
|
||||
mPreviewAdapter = previewAdapter;
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void setCurrentItem(int currentItem) {
|
||||
Preconditions.checkNotNull(mPreviewAdapter,
|
||||
"Preview adapter is null, you should init the preview adapter first");
|
||||
|
||||
if (currentItem != mCurrentItem) {
|
||||
mCurrentItem = currentItem;
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int getCurrentItem() {
|
||||
return mCurrentItem;
|
||||
}
|
||||
|
||||
private void updateAdapterIfNeeded(ViewPager viewPager, DotsPageIndicator pageIndicator,
|
||||
PreviewPagerAdapter previewAdapter) {
|
||||
if (viewPager.getAdapter() == previewAdapter) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewPager.setAdapter(previewAdapter);
|
||||
|
||||
if (previewAdapter != null) {
|
||||
pageIndicator.setViewPager(viewPager);
|
||||
} else {
|
||||
mCurrentItem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePagerAndIndicator(ViewPager viewPager, DotsPageIndicator pageIndicator) {
|
||||
if (viewPager.getAdapter() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewPager.getCurrentItem() != mCurrentItem) {
|
||||
viewPager.setCurrentItem(mCurrentItem);
|
||||
}
|
||||
|
||||
pageIndicator.setVisibility(
|
||||
viewPager.getAdapter().getCount() > 1 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setLayoutResource(R.layout.accessibility_text_reading_preview);
|
||||
}
|
||||
|
||||
void notifyPreviewPagerChanged(int pagerIndex) {
|
||||
Preconditions.checkNotNull(mPreviewAdapter,
|
||||
"Preview adapter is null, you should init the preview adapter first");
|
||||
|
||||
if (pagerIndex != mLastLayerIndex) {
|
||||
mPreviewAdapter.setPreviewLayer(pagerIndex, mLastLayerIndex, getCurrentItem(),
|
||||
/* animate= */ false);
|
||||
}
|
||||
|
||||
mLastLayerIndex = pagerIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.Context;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.instrumentation.SettingsStatsLog;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
/**
|
||||
* The controller of the reset button in the text and reading options page.
|
||||
*/
|
||||
class TextReadingResetController extends BasePreferenceController {
|
||||
private final View.OnClickListener mOnResetClickListener;
|
||||
|
||||
@EntryPoint
|
||||
private int mEntryPoint;
|
||||
|
||||
TextReadingResetController(Context context, String preferenceKey,
|
||||
@Nullable View.OnClickListener listener) {
|
||||
super(context, preferenceKey);
|
||||
mOnResetClickListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
final LayoutPreference layoutPreference = screen.findPreference(getPreferenceKey());
|
||||
final View view = layoutPreference.findViewById(R.id.reset_button);
|
||||
view.setOnClickListener(v -> {
|
||||
if (mOnResetClickListener != null) {
|
||||
mOnResetClickListener.onClick(v);
|
||||
|
||||
SettingsStatsLog.write(
|
||||
SettingsStatsLog.ACCESSIBILITY_TEXT_READING_OPTIONS_CHANGED,
|
||||
AccessibilityStatsLogUtils.convertToItemKeyName(getPreferenceKey()),
|
||||
/* reset */ -1,
|
||||
AccessibilityStatsLogUtils.convertToEntryPoint(mEntryPoint));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point is used for logging.
|
||||
*
|
||||
* @param entryPoint from which settings page
|
||||
*/
|
||||
void setEntryPoint(@EntryPoint int entryPoint) {
|
||||
mEntryPoint = entryPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for resetting to default state.
|
||||
*/
|
||||
interface ResetStateListener {
|
||||
/**
|
||||
* Called when the reset button was clicked.
|
||||
*/
|
||||
void resetState();
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
@@ -47,6 +47,7 @@ import android.widget.Switch;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
@@ -59,20 +60,16 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
ToggleFeaturePreferenceFragment {
|
||||
|
||||
private static final String TAG = "ToggleAccessibilityServicePreferenceFragment";
|
||||
private static final String KEY_HAS_LOGGED = "has_logged";
|
||||
private AtomicBoolean mIsDialogShown = new AtomicBoolean(/* initialValue= */ false);
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
private final SettingsContentObserver mSettingsContentObserver =
|
||||
new SettingsContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
updateSwitchBarToggleSwitch();
|
||||
}
|
||||
};
|
||||
|
||||
private Dialog mDialog;
|
||||
private Dialog mWarningDialog;
|
||||
private ComponentName mTileComponentName;
|
||||
private BroadcastReceiver mPackageRemovedReceiver;
|
||||
private boolean mDisabledStateLogged = false;
|
||||
private long mStartTimeMillsForLogging = 0;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -97,6 +94,18 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
if (savedInstanceState.containsKey(KEY_HAS_LOGGED)) {
|
||||
mDisabledStateLogged = savedInstanceState.getBoolean(KEY_HAS_LOGGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerKeysToObserverCallback(
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
super.registerKeysToObserverCallback(contentObserver);
|
||||
contentObserver.registerObserverCallback(key -> updateSwitchBarToggleSwitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,13 +123,28 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateSwitchBarToggleSwitch();
|
||||
mSettingsContentObserver.register(getContentResolver());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
if (mStartTimeMillsForLogging > 0) {
|
||||
outState.putBoolean(KEY_HAS_LOGGED, mDisabledStateLogged);
|
||||
}
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
|
||||
logAccessibilityServiceEnabled(toggledService, enabled);
|
||||
if (!enabled) {
|
||||
logDisabledState(toggledService.getPackageName());
|
||||
}
|
||||
AccessibilityUtils.setAccessibilityServiceState(getPrefContext(), toggledService, enabled);
|
||||
}
|
||||
|
||||
@@ -146,55 +170,46 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(int dialogId) {
|
||||
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
switch (dialogId) {
|
||||
case DialogEnums.ENABLE_WARNING_FROM_TOGGLE: {
|
||||
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
case DialogEnums.ENABLE_WARNING_FROM_TOGGLE:
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
mDialog = AccessibilityServiceWarning
|
||||
mWarningDialog = AccessibilityServiceWarning
|
||||
.createCapabilitiesDialog(getPrefContext(), info,
|
||||
this::onDialogButtonFromEnableToggleClicked,
|
||||
this::onDialogButtonFromUninstallClicked);
|
||||
break;
|
||||
}
|
||||
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE: {
|
||||
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
return mWarningDialog;
|
||||
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT_TOGGLE:
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
mDialog = AccessibilityServiceWarning
|
||||
mWarningDialog = AccessibilityServiceWarning
|
||||
.createCapabilitiesDialog(getPrefContext(), info,
|
||||
this::onDialogButtonFromShortcutToggleClicked,
|
||||
this::onDialogButtonFromUninstallClicked);
|
||||
break;
|
||||
}
|
||||
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT: {
|
||||
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
return mWarningDialog;
|
||||
case DialogEnums.ENABLE_WARNING_FROM_SHORTCUT:
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
mDialog = AccessibilityServiceWarning
|
||||
mWarningDialog = AccessibilityServiceWarning
|
||||
.createCapabilitiesDialog(getPrefContext(), info,
|
||||
this::onDialogButtonFromShortcutClicked,
|
||||
this::onDialogButtonFromUninstallClicked);
|
||||
break;
|
||||
}
|
||||
case DialogEnums.DISABLE_WARNING_FROM_TOGGLE: {
|
||||
final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
|
||||
return mWarningDialog;
|
||||
case DialogEnums.DISABLE_WARNING_FROM_TOGGLE:
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
mDialog = AccessibilityServiceWarning
|
||||
mWarningDialog = AccessibilityServiceWarning
|
||||
.createDisableDialog(getPrefContext(), info,
|
||||
this::onDialogButtonFromDisableToggleClicked);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
mDialog = super.onCreateDialog(dialogId);
|
||||
}
|
||||
return mWarningDialog;
|
||||
default:
|
||||
return super.onCreateDialog(dialogId);
|
||||
}
|
||||
return mDialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,6 +234,29 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
ComponentName getTileComponentName() {
|
||||
return mTileComponentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
|
||||
final ComponentName componentName = getTileComponentName();
|
||||
if (componentName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final CharSequence tileName = loadTileLabel(getPrefContext(), componentName);
|
||||
if (tileName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int titleResId = type == QuickSettingsTooltipType.GUIDE_TO_EDIT
|
||||
? R.string.accessibility_service_qs_tooltip_content
|
||||
: R.string.accessibility_service_auto_added_qs_tooltip_content;
|
||||
return getString(titleResId, tileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSwitchBarToggleSwitch() {
|
||||
final boolean checked = isAccessibilityServiceEnabled();
|
||||
@@ -353,6 +391,14 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
// Get Accessibility service name.
|
||||
mPackageName = getAccessibilityServiceInfo().getResolveInfo().loadLabel(
|
||||
getPackageManager());
|
||||
|
||||
if (arguments.containsKey(AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME)) {
|
||||
final String tileServiceComponentName = arguments.getString(
|
||||
AccessibilitySettings.EXTRA_TILE_SERVICE_COMPONENT_NAME);
|
||||
mTileComponentName = ComponentName.unflattenFromString(tileServiceComponentName);
|
||||
}
|
||||
|
||||
mStartTimeMillsForLogging = arguments.getLong(AccessibilitySettings.EXTRA_TIME_FOR_LOGGING);
|
||||
}
|
||||
|
||||
private void onDialogButtonFromDisableToggleClicked(DialogInterface dialog, int which) {
|
||||
@@ -380,7 +426,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
}
|
||||
|
||||
private void onDialogButtonFromUninstallClicked() {
|
||||
mDialog.dismiss();
|
||||
mWarningDialog.dismiss();
|
||||
final Intent uninstallIntent = createUninstallPackageActivityIntent();
|
||||
if (uninstallIntent == null) {
|
||||
return;
|
||||
@@ -414,12 +460,12 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
mIsDialogShown.set(false);
|
||||
showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
|
||||
}
|
||||
mDialog.dismiss();
|
||||
mWarningDialog.dismiss();
|
||||
}
|
||||
|
||||
private void onDenyButtonFromEnableToggleClicked() {
|
||||
handleConfirmServiceEnabled(/* confirmed= */ false);
|
||||
mDialog.dismiss();
|
||||
mWarningDialog.dismiss();
|
||||
}
|
||||
|
||||
void onDialogButtonFromShortcutToggleClicked(View view) {
|
||||
@@ -443,7 +489,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
mIsDialogShown.set(false);
|
||||
showPopupDialog(DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL);
|
||||
|
||||
mDialog.dismiss();
|
||||
mWarningDialog.dismiss();
|
||||
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
}
|
||||
@@ -451,7 +497,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
private void onDenyButtonFromShortcutToggleClicked() {
|
||||
mShortcutPreference.setChecked(false);
|
||||
|
||||
mDialog.dismiss();
|
||||
mWarningDialog.dismiss();
|
||||
}
|
||||
|
||||
void onDialogButtonFromShortcutClicked(View view) {
|
||||
@@ -469,11 +515,11 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
mIsDialogShown.set(false);
|
||||
showPopupDialog(DialogEnums.EDIT_SHORTCUT);
|
||||
|
||||
mDialog.dismiss();
|
||||
mWarningDialog.dismiss();
|
||||
}
|
||||
|
||||
private void onDenyButtonFromShortcutClicked() {
|
||||
mDialog.dismiss();
|
||||
mWarningDialog.dismiss();
|
||||
}
|
||||
|
||||
private boolean onPreferenceClick(boolean isChecked) {
|
||||
@@ -506,4 +552,13 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
private void logDisabledState(String packageName) {
|
||||
if (mStartTimeMillsForLogging > 0 && !mDisabledStateLogged) {
|
||||
AccessibilityStatsLogUtils.logDisableNonA11yCategoryService(
|
||||
packageName,
|
||||
SystemClock.elapsedRealtime() - mStartTimeMillsForLogging);
|
||||
mDisabledStateLogged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class ToggleAutoclickFooterPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLearnMoreContentDescription() {
|
||||
protected String getLearnMoreText() {
|
||||
return mContext.getString(
|
||||
R.string.accessibility_autoclick_footer_learn_more_content_description);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
import com.android.settingslib.widget.RadioButtonPreference;
|
||||
import com.android.settingslib.widget.SelectorWithWidgetPreference;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -43,7 +43,7 @@ import java.util.Map;
|
||||
* Controller class that controls accessibility autoclick settings.
|
||||
*/
|
||||
public class ToggleAutoclickPreferenceController extends BasePreferenceController implements
|
||||
LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin {
|
||||
LifecycleObserver, SelectorWithWidgetPreference.OnClickListener, PreferenceControllerMixin {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String CONTROL_AUTOCLICK_DELAY_SECURE =
|
||||
@@ -67,7 +67,7 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle
|
||||
private final ContentResolver mContentResolver;
|
||||
private final Resources mResources;
|
||||
private OnChangeListener mOnChangeListener;
|
||||
private RadioButtonPreference mDelayModePref;
|
||||
private SelectorWithWidgetPreference mDelayModePref;
|
||||
|
||||
/**
|
||||
* Seek bar preference for autoclick delay value. The seek bar has values between 0 and
|
||||
@@ -109,7 +109,7 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mDelayModePref = (RadioButtonPreference)
|
||||
mDelayModePref = (SelectorWithWidgetPreference)
|
||||
screen.findPreference(getPreferenceKey());
|
||||
mDelayModePref.setOnClickListener(this);
|
||||
mSeekBerPreference = (LayoutPreference) screen.findPreference(KEY_AUTOCLICK_CUSTOM_SEEKBAR);
|
||||
@@ -117,7 +117,7 @@ public class ToggleAutoclickPreferenceController extends BasePreferenceControlle
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRadioButtonClicked(RadioButtonPreference preference) {
|
||||
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
|
||||
final int value = mAccessibilityAutoclickKeyToValueMap.get(mPreferenceKey);
|
||||
handleRadioButtonPreferenceChange(value);
|
||||
if (mOnChangeListener != null) {
|
||||
|
||||
@@ -17,21 +17,23 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME;
|
||||
import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -41,8 +43,6 @@ import java.util.List;
|
||||
public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePreferenceFragment {
|
||||
|
||||
private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED;
|
||||
private final Handler mHandler = new Handler();
|
||||
private SettingsContentObserver mSettingsContentObserver;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -51,6 +51,14 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
|
||||
@Override
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
final boolean isEnabled = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
|
||||
if (enabled == isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
showQuickSettingsTooltipIfNeeded(QuickSettingsTooltipType.GUIDE_TO_DIRECT_USE);
|
||||
}
|
||||
logAccessibilityServiceEnabled(mComponentName, enabled);
|
||||
Settings.Secure.putInt(getContentResolver(), ENABLED, enabled ? ON : OFF);
|
||||
}
|
||||
@@ -72,8 +80,8 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.accessibility_display_inversion_shortcut_title);
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getText(R.string.accessibility_display_inversion_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,31 +90,34 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
mComponentName = COLOR_INVERSION_COMPONENT_NAME;
|
||||
mPackageName = 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.accessibility_color_inversion_banner))
|
||||
.build();
|
||||
final List<String> enableServiceFeatureKeys = new ArrayList<>(/* initialCapacity= */ 1);
|
||||
enableServiceFeatureKeys.add(ENABLED);
|
||||
mSettingsContentObserver = new SettingsContentObserver(mHandler, enableServiceFeatureKeys) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
updateSwitchBarToggleSwitch();
|
||||
}
|
||||
};
|
||||
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
updateFooterPreference();
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerKeysToObserverCallback(
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
super.registerKeysToObserverCallback(contentObserver);
|
||||
|
||||
final List<String> enableServiceFeatureKeys = new ArrayList<>(/* initialCapacity= */ 1);
|
||||
enableServiceFeatureKeys.add(ENABLED);
|
||||
contentObserver.registerKeysToObserverCallback(enableServiceFeatureKeys,
|
||||
key -> updateSwitchBarToggleSwitch());
|
||||
}
|
||||
|
||||
private void updateFooterPreference() {
|
||||
final String title = getPrefContext().getString(
|
||||
R.string.accessibility_color_inversion_about_title);
|
||||
final String learnMoreContentDescription = getPrefContext().getString(
|
||||
final String learnMoreText = getPrefContext().getString(
|
||||
R.string.accessibility_color_inversion_footer_learn_more_content_description);
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreContentDescription);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreText);
|
||||
mFooterPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
@@ -114,12 +125,10 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateSwitchBarToggleSwitch();
|
||||
mSettingsContentObserver.register(getContentResolver());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mSettingsContentObserver.unregister(getContentResolver());
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@@ -134,6 +143,18 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
|
||||
mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
ComponentName getTileComponentName() {
|
||||
return COLOR_INVERSION_TILE_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSwitchBarToggleSwitch() {
|
||||
final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME;
|
||||
import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -35,6 +35,7 @@ import android.view.ViewGroup;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -51,10 +52,11 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
|
||||
private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED;
|
||||
private static final String KEY_PREVIEW = "daltonizer_preview";
|
||||
private static final String KEY_CATEGORY_MODE = "daltonizer_mode_category";
|
||||
private static final String KEY_DEUTERANOMALY = "daltonizer_mode_deuteranomaly";
|
||||
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";
|
||||
private static final List<AbstractPreferenceController> sControllers = new ArrayList<>();
|
||||
private final Handler mHandler = new Handler();
|
||||
private SettingsContentObserver mSettingsContentObserver;
|
||||
|
||||
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
|
||||
Lifecycle lifecycle) {
|
||||
@@ -84,36 +86,43 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
mComponentName = DALTONIZER_COMPONENT_NAME;
|
||||
mPackageName = getText(R.string.accessibility_display_daltonizer_preference_title);
|
||||
mHtmlDescription = getText(R.string.accessibility_display_daltonizer_preference_subtitle);
|
||||
final List<String> enableServiceFeatureKeys = new ArrayList<>(/* initialCapacity= */ 1);
|
||||
enableServiceFeatureKeys.add(ENABLED);
|
||||
mSettingsContentObserver = new SettingsContentObserver(mHandler, enableServiceFeatureKeys) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
updateSwitchBarToggleSwitch();
|
||||
}
|
||||
};
|
||||
|
||||
mTopIntroTitle = getText(R.string.accessibility_daltonizer_about_intro_text);
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
updateFooterPreference();
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerKeysToObserverCallback(
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
super.registerKeysToObserverCallback(contentObserver);
|
||||
|
||||
final List<String> enableServiceFeatureKeys = new ArrayList<>(/* initialCapacity= */ 1);
|
||||
enableServiceFeatureKeys.add(ENABLED);
|
||||
contentObserver.registerKeysToObserverCallback(enableServiceFeatureKeys,
|
||||
key -> updateSwitchBarToggleSwitch());
|
||||
}
|
||||
|
||||
private void updateFooterPreference() {
|
||||
final String title = getPrefContext()
|
||||
.getString(R.string.accessibility_daltonizer_about_title);
|
||||
final String learnMoreContentDescription = getPrefContext()
|
||||
final String learnMoreText = getPrefContext()
|
||||
.getString(R.string.accessibility_daltonizer_footer_learn_more_content_description);
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreContentDescription);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreText);
|
||||
mFooterPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
/** Customizes the order by preference key. */
|
||||
protected List<String> getPreferenceOrderList() {
|
||||
final List<String> lists = new ArrayList<>();
|
||||
lists.add(KEY_TOP_INTRO_PREFERENCE);
|
||||
lists.add(KEY_PREVIEW);
|
||||
lists.add(KEY_USE_SERVICE_PREFERENCE);
|
||||
lists.add(KEY_CATEGORY_MODE);
|
||||
lists.add(KEY_DEUTERANOMALY);
|
||||
lists.add(KEY_PROTANOMALY);
|
||||
lists.add(KEY_TRITANOMEALY);
|
||||
lists.add(KEY_GRAYSCALE);
|
||||
lists.add(KEY_GENERAL_CATEGORY);
|
||||
lists.add(KEY_HTML_DESCRIPTION_PREFERENCE);
|
||||
return lists;
|
||||
@@ -123,8 +132,6 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateSwitchBarToggleSwitch();
|
||||
mSettingsContentObserver.register(getContentResolver());
|
||||
|
||||
for (AbstractPreferenceController controller :
|
||||
buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
|
||||
((DaltonizerRadioButtonPreferenceController) controller).setOnChangeListener(this);
|
||||
@@ -135,7 +142,6 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mSettingsContentObserver.unregister(getContentResolver());
|
||||
for (AbstractPreferenceController controller :
|
||||
buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
|
||||
((DaltonizerRadioButtonPreferenceController) controller).setOnChangeListener(null);
|
||||
@@ -160,6 +166,14 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
|
||||
@Override
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
final boolean isEnabled = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
|
||||
if (enabled == isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
showQuickSettingsTooltipIfNeeded(QuickSettingsTooltipType.GUIDE_TO_DIRECT_USE);
|
||||
}
|
||||
logAccessibilityServiceEnabled(mComponentName, enabled);
|
||||
Settings.Secure.putInt(getContentResolver(), ENABLED, enabled ? ON : OFF);
|
||||
}
|
||||
@@ -176,8 +190,8 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.accessibility_daltonizer_shortcut_title);
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getText(R.string.accessibility_daltonizer_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -186,6 +200,18 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
|
||||
mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
ComponentName getTileComponentName() {
|
||||
return DALTONIZER_TILE_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
|
||||
return getText(type == QuickSettingsTooltipType.GUIDE_TO_EDIT
|
||||
? R.string.accessibility_color_correction_qs_tooltip_content
|
||||
: R.string.accessibility_color_correction_auto_added_qs_tooltip_content);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSwitchBarToggleSwitch() {
|
||||
final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
|
||||
|
||||
@@ -25,7 +25,9 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
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;
|
||||
@@ -33,6 +35,7 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -53,6 +56,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
||||
@@ -60,6 +64,7 @@ import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
import com.android.settingslib.accessibility.AccessibilityUtils;
|
||||
import com.android.settingslib.widget.IllustrationPreference;
|
||||
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
||||
import com.android.settingslib.widget.TopIntroPreference;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
@@ -74,6 +79,7 @@ import java.util.Locale;
|
||||
public abstract class ToggleFeaturePreferenceFragment extends SettingsPreferenceFragment
|
||||
implements ShortcutPreference.OnClickCallback, OnMainSwitchChangeListener {
|
||||
|
||||
protected TopIntroPreference mTopIntroPreference;
|
||||
protected SettingsMainSwitchPreference mToggleServiceSwitchPreference;
|
||||
protected ShortcutPreference mShortcutPreference;
|
||||
protected Preference mSettingsPreference;
|
||||
@@ -89,21 +95,29 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
protected Uri mImageUri;
|
||||
private CharSequence mDescription;
|
||||
protected CharSequence mHtmlDescription;
|
||||
protected CharSequence mTopIntroTitle;
|
||||
|
||||
private static final String DRAWABLE_FOLDER = "drawable";
|
||||
protected static final String KEY_TOP_INTRO_PREFERENCE = "top_intro";
|
||||
protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service";
|
||||
public static final String KEY_GENERAL_CATEGORY = "general_categories";
|
||||
protected static final String KEY_HTML_DESCRIPTION_PREFERENCE = "html_description";
|
||||
private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
|
||||
public static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
|
||||
protected static final String KEY_SAVED_USER_SHORTCUT_TYPE = "shortcut_type";
|
||||
protected static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
|
||||
protected static final String KEY_SAVED_QS_TOOLTIP_TYPE = "qs_tooltip_type";
|
||||
protected static final String KEY_ANIMATED_IMAGE = "animated_image";
|
||||
|
||||
private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
|
||||
private SettingsContentObserver mSettingsContentObserver;
|
||||
private AccessibilitySettingsContentObserver mSettingsContentObserver;
|
||||
|
||||
private CheckBox mSoftwareTypeCheckBox;
|
||||
private CheckBox mHardwareTypeCheckBox;
|
||||
|
||||
private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
|
||||
private boolean mNeedsQSTooltipReshow = false;
|
||||
private int mNeedsQSTooltipType = QuickSettingsTooltipType.GUIDE_TO_EDIT;
|
||||
|
||||
public static final int NOT_SET = -1;
|
||||
// Save user's shortcutType value when savedInstance has value (e.g. device rotated).
|
||||
protected int mSavedCheckBoxValue = NOT_SET;
|
||||
@@ -129,13 +143,20 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// Restore the user shortcut type.
|
||||
if (savedInstanceState != null && savedInstanceState.containsKey(
|
||||
KEY_SAVED_USER_SHORTCUT_TYPE)) {
|
||||
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE, NOT_SET);
|
||||
// Restore the user shortcut type and tooltip.
|
||||
if (savedInstanceState != null) {
|
||||
if (savedInstanceState.containsKey(KEY_SAVED_USER_SHORTCUT_TYPE)) {
|
||||
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE,
|
||||
NOT_SET);
|
||||
}
|
||||
if (savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_RESHOW)) {
|
||||
mNeedsQSTooltipReshow = savedInstanceState.getBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW);
|
||||
}
|
||||
if (savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_TYPE)) {
|
||||
mNeedsQSTooltipType = savedInstanceState.getInt(KEY_SAVED_QS_TOOLTIP_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
setupDefaultShortcutIfNecessary(getPrefContext());
|
||||
final int resId = getPreferenceScreenResId();
|
||||
if (resId <= 0) {
|
||||
final PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(
|
||||
@@ -143,17 +164,21 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
setPreferenceScreen(preferenceScreen);
|
||||
}
|
||||
|
||||
final List<String> shortcutFeatureKeys = getFeatureSettingsKeys();
|
||||
mSettingsContentObserver = new SettingsContentObserver(new Handler(), shortcutFeatureKeys) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
updateShortcutPreferenceData();
|
||||
updateShortcutPreference();
|
||||
}
|
||||
};
|
||||
mSettingsContentObserver = new AccessibilitySettingsContentObserver(new Handler());
|
||||
registerKeysToObserverCallback(mSettingsContentObserver);
|
||||
}
|
||||
|
||||
protected List<String> getFeatureSettingsKeys() {
|
||||
protected void registerKeysToObserverCallback(
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
final List<String> shortcutFeatureKeys = getShortcutFeatureSettingsKeys();
|
||||
|
||||
contentObserver.registerKeysToObserverCallback(shortcutFeatureKeys, key -> {
|
||||
updateShortcutPreferenceData();
|
||||
updateShortcutPreference();
|
||||
});
|
||||
}
|
||||
|
||||
protected List<String> getShortcutFeatureSettingsKeys() {
|
||||
final List<String> shortcutFeatureKeys = new ArrayList<>();
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
|
||||
shortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
|
||||
@@ -166,6 +191,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
// Need to be called as early as possible. Protected variables will be assigned here.
|
||||
onProcessArguments(getArguments());
|
||||
|
||||
initTopIntroPreference();
|
||||
initAnimatedImagePreference();
|
||||
initToggleServiceSwitchPreference();
|
||||
initGeneralCategory();
|
||||
@@ -194,6 +220,13 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
switchBar.hide();
|
||||
|
||||
updatePreferenceOrder();
|
||||
|
||||
// Reshow tooltip when activity recreate, such as rotate device.
|
||||
if (mNeedsQSTooltipReshow) {
|
||||
getView().post(this::showQuickSettingsTooltipIfNeeded);
|
||||
}
|
||||
|
||||
writeDefaultShortcutTargetServiceToSettingsIfNeeded(getPrefContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,6 +260,10 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
if (value != NOT_SET) {
|
||||
outState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, value);
|
||||
}
|
||||
if (mTooltipWindow != null) {
|
||||
outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, mTooltipWindow.isShowing());
|
||||
outState.putInt(KEY_SAVED_QS_TOOLTIP_TYPE, mNeedsQSTooltipType);
|
||||
}
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@@ -234,19 +271,17 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
public Dialog onCreateDialog(int dialogId) {
|
||||
switch (dialogId) {
|
||||
case DialogEnums.EDIT_SHORTCUT:
|
||||
final CharSequence dialogTitle = getPrefContext().getString(
|
||||
R.string.accessibility_shortcut_title, mPackageName);
|
||||
final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
|
||||
? DialogType.EDIT_SHORTCUT_GENERIC_SUW : DialogType.EDIT_SHORTCUT_GENERIC;
|
||||
mDialog = AccessibilityDialogUtils.showEditShortcutDialog(
|
||||
getPrefContext(), dialogType, dialogTitle,
|
||||
getPrefContext(), dialogType, getShortcutTitle(),
|
||||
this::callOnAlertDialogCheckboxClicked);
|
||||
setupEditShortcutDialog(mDialog);
|
||||
return mDialog;
|
||||
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
|
||||
mDialog = AccessibilityGestureNavigationTutorial
|
||||
.createAccessibilityTutorialDialog(getPrefContext(),
|
||||
getUserShortcutTypes());
|
||||
getUserShortcutTypes(), this::callOnTutorialDialogButtonClicked);
|
||||
mDialog.setCanceledOnTouchOutside(false);
|
||||
return mDialog;
|
||||
default:
|
||||
@@ -292,18 +327,27 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
*/
|
||||
abstract int getUserShortcutTypes();
|
||||
|
||||
/** Returns the accessibility tile component name. */
|
||||
abstract ComponentName getTileComponentName();
|
||||
|
||||
/** Returns the accessibility tile tooltip content. */
|
||||
abstract CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type);
|
||||
|
||||
protected void updateToggleServiceTitle(SettingsMainSwitchPreference switchPreference) {
|
||||
final CharSequence title =
|
||||
getString(R.string.accessibility_service_primary_switch_title, mPackageName);
|
||||
switchPreference.setTitle(title);
|
||||
}
|
||||
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
final CharSequence title = getString(R.string.accessibility_shortcut_title, mPackageName);
|
||||
shortcutPreference.setTitle(title);
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getString(R.string.accessibility_shortcut_title, mPackageName);
|
||||
}
|
||||
|
||||
protected abstract void onPreferenceToggled(String preferenceKey, boolean enabled);
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
if (enabled) {
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onInstallSwitchPreferenceToggleSwitch() {
|
||||
// Implement this to set a checked listener.
|
||||
@@ -354,11 +398,17 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
mHtmlDescription = arguments.getCharSequence(
|
||||
AccessibilitySettings.EXTRA_HTML_DESCRIPTION);
|
||||
}
|
||||
|
||||
// Intro.
|
||||
if (arguments.containsKey(AccessibilitySettings.EXTRA_INTRO)) {
|
||||
mTopIntroTitle = arguments.getCharSequence(AccessibilitySettings.EXTRA_INTRO);
|
||||
}
|
||||
}
|
||||
|
||||
/** Customizes the order by preference key. */
|
||||
protected List<String> getPreferenceOrderList() {
|
||||
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(KEY_GENERAL_CATEGORY);
|
||||
@@ -427,6 +477,17 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
getPreferenceScreen().addPreference(illustrationPreference);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void initTopIntroPreference() {
|
||||
if (TextUtils.isEmpty(mTopIntroTitle)) {
|
||||
return;
|
||||
}
|
||||
mTopIntroPreference = new TopIntroPreference(getPrefContext());
|
||||
mTopIntroPreference.setKey(KEY_TOP_INTRO_PREFERENCE);
|
||||
mTopIntroPreference.setTitle(mTopIntroTitle);
|
||||
getPreferenceScreen().addPreference(mTopIntroPreference);
|
||||
}
|
||||
|
||||
private void initToggleServiceSwitchPreference() {
|
||||
mToggleServiceSwitchPreference = new SettingsMainSwitchPreference(getPrefContext());
|
||||
mToggleServiceSwitchPreference.setKey(KEY_USE_SERVICE_PREFERENCE);
|
||||
@@ -452,8 +513,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
mShortcutPreference.setPersistent(false);
|
||||
mShortcutPreference.setKey(getShortcutPreferenceKey());
|
||||
mShortcutPreference.setOnClickCallback(this);
|
||||
|
||||
updateShortcutTitle(mShortcutPreference);
|
||||
mShortcutPreference.setTitle(getShortcutTitle());
|
||||
|
||||
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
|
||||
generalCategory.addPreference(mShortcutPreference);
|
||||
@@ -501,13 +561,6 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
createFooterPreference(getPreferenceScreen(), mDescription,
|
||||
getString(R.string.accessibility_introduction_title, mPackageName));
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(mHtmlDescription) && TextUtils.isEmpty(mDescription)) {
|
||||
final CharSequence defaultDescription =
|
||||
getText(R.string.accessibility_service_default_description);
|
||||
createFooterPreference(getPreferenceScreen(), defaultDescription,
|
||||
getString(R.string.accessibility_introduction_title, mPackageName));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -639,6 +692,17 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
null, LocaleUtils.getConcatenatedString(list));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be invoked when a button in the tutorial dialog is clicked.
|
||||
*
|
||||
* @param dialog The dialog that received the click
|
||||
* @param which The button that was clicked
|
||||
*/
|
||||
private void callOnTutorialDialogButtonClicked(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be invoked when a button in the edit shortcut dialog is clicked.
|
||||
*
|
||||
@@ -651,12 +715,21 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
}
|
||||
|
||||
final int value = getShortcutTypeCheckBoxValue();
|
||||
|
||||
saveNonEmptyUserShortcutType(value);
|
||||
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), value, mComponentName);
|
||||
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~value, mComponentName);
|
||||
mShortcutPreference.setChecked(value != UserShortcutType.EMPTY);
|
||||
final boolean shortcutAssigned = value != UserShortcutType.EMPTY;
|
||||
mShortcutPreference.setChecked(shortcutAssigned);
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
|
||||
if (mHardwareTypeCheckBox.isChecked()) {
|
||||
AccessibilityUtil.skipVolumeShortcutDialogTimeoutRestriction(getPrefContext());
|
||||
}
|
||||
|
||||
// Show the quick setting tooltip if the shortcut assigned in the first time
|
||||
if (shortcutAssigned) {
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateShortcutPreferenceData() {
|
||||
@@ -716,8 +789,22 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
|
||||
/**
|
||||
* Setups a configurable default if the setting has never been set.
|
||||
*
|
||||
* TODO(b/228562075): Remove this function when correcting the format in config file
|
||||
* `config_defaultAccessibilityService`.
|
||||
*/
|
||||
private static void setupDefaultShortcutIfNecessary(Context context) {
|
||||
private void writeDefaultShortcutTargetServiceToSettingsIfNeeded(Context context) {
|
||||
if (mComponentName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ComponentName defaultService = ComponentName.unflattenFromString(context.getString(
|
||||
com.android.internal.R.string.config_defaultAccessibilityService));
|
||||
// write default accessibility service only when user enter into corresponding page.
|
||||
if (!mComponentName.equals(defaultService)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String targetKey = Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
|
||||
String targetString = Settings.Secure.getString(context.getContentResolver(), targetKey);
|
||||
if (!TextUtils.isEmpty(targetString)) {
|
||||
@@ -766,4 +853,61 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
||||
mComponentName.flattenToString(), type);
|
||||
PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the quick settings tooltip if the quick settings feature is assigned. The tooltip only
|
||||
* shows once.
|
||||
*
|
||||
* @param type The quick settings tooltip type
|
||||
*/
|
||||
protected void showQuickSettingsTooltipIfNeeded(@QuickSettingsTooltipType int type) {
|
||||
mNeedsQSTooltipType = type;
|
||||
showQuickSettingsTooltipIfNeeded();
|
||||
}
|
||||
|
||||
private void showQuickSettingsTooltipIfNeeded() {
|
||||
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;
|
||||
}
|
||||
|
||||
/** Returns user visible name of the tile by given {@link ComponentName}. */
|
||||
protected CharSequence loadTileLabel(Context context, ComponentName componentName) {
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
final Intent queryIntent = new Intent(TileService.ACTION_QS_TILE);
|
||||
final List<ResolveInfo> resolveInfos =
|
||||
packageManager.queryIntentServices(queryIntent, PackageManager.GET_META_DATA);
|
||||
for (ResolveInfo info : resolveInfos) {
|
||||
final ServiceInfo serviceInfo = info.serviceInfo;
|
||||
if (TextUtils.equals(componentName.getPackageName(), serviceInfo.packageName)
|
||||
&& TextUtils.equals(componentName.getClassName(), serviceInfo.name)) {
|
||||
return serviceInfo.loadLabel(packageManager);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,17 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
|
||||
import static com.android.settings.accessibility.AccessibilityStatsLogUtils.logAccessibilityServiceEnabled;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.ColorDisplayManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -31,8 +35,8 @@ import android.view.ViewGroup;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.internal.accessibility.AccessibilityShortcutController;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.widget.SeekBarPreference;
|
||||
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||
@@ -50,8 +54,6 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
private static final String KEY_INTENSITY = "rbc_intensity";
|
||||
private static final String KEY_PERSIST = "rbc_persist";
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
private SettingsContentObserver mSettingsContentObserver;
|
||||
private ReduceBrightColorsIntensityPreferenceController mRbcIntensityPreferenceController;
|
||||
private ReduceBrightColorsPersistencePreferenceController mRbcPersistencePreferenceController;
|
||||
private ColorDisplayManager mColorDisplayManager;
|
||||
@@ -64,23 +66,16 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
.authority(getPrefContext().getPackageName())
|
||||
.appendPath(String.valueOf(R.raw.extra_dim_banner))
|
||||
.build();
|
||||
mComponentName = AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
|
||||
mComponentName = REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
|
||||
mPackageName = getText(R.string.reduce_bright_colors_preference_title);
|
||||
mHtmlDescription = getText(R.string.reduce_bright_colors_preference_subtitle);
|
||||
final List<String> enableServiceFeatureKeys = new ArrayList<>(/* initialCapacity= */ 1);
|
||||
enableServiceFeatureKeys.add(REDUCE_BRIGHT_COLORS_ACTIVATED_KEY);
|
||||
mTopIntroTitle = getText(R.string.reduce_bright_colors_preference_intro_text);
|
||||
mRbcIntensityPreferenceController =
|
||||
new ReduceBrightColorsIntensityPreferenceController(getContext(), KEY_INTENSITY);
|
||||
mRbcPersistencePreferenceController =
|
||||
new ReduceBrightColorsPersistencePreferenceController(getContext(), KEY_PERSIST);
|
||||
mRbcIntensityPreferenceController.displayPreference(getPreferenceScreen());
|
||||
mRbcPersistencePreferenceController.displayPreference(getPreferenceScreen());
|
||||
mSettingsContentObserver = new SettingsContentObserver(mHandler, enableServiceFeatureKeys) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
updateSwitchBarToggleSwitch();
|
||||
}
|
||||
};
|
||||
mColorDisplayManager = getContext().getSystemService(ColorDisplayManager.class);
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
// Parent sets the title when creating the view, so set it after calling super
|
||||
@@ -90,6 +85,17 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerKeysToObserverCallback(
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
super.registerKeysToObserverCallback(contentObserver);
|
||||
|
||||
final List<String> enableServiceFeatureKeys = new ArrayList<>(/* initialCapacity= */ 1);
|
||||
enableServiceFeatureKeys.add(REDUCE_BRIGHT_COLORS_ACTIVATED_KEY);
|
||||
contentObserver.registerKeysToObserverCallback(enableServiceFeatureKeys,
|
||||
key -> updateSwitchBarToggleSwitch());
|
||||
}
|
||||
|
||||
private void updateGeneralCategoryOrder() {
|
||||
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
|
||||
final SeekBarPreference intensity = findPreference(KEY_INTENSITY);
|
||||
@@ -117,12 +123,10 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateSwitchBarToggleSwitch();
|
||||
mSettingsContentObserver.register(getContentResolver());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mSettingsContentObserver.unregister(getContentResolver());
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@@ -144,7 +148,10 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
|
||||
@Override
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
AccessibilityStatsLogUtils.logAccessibilityServiceEnabled(mComponentName, enabled);
|
||||
if (enabled) {
|
||||
showQuickSettingsTooltipIfNeeded(QuickSettingsTooltipType.GUIDE_TO_DIRECT_USE);
|
||||
}
|
||||
logAccessibilityServiceEnabled(mComponentName, enabled);
|
||||
mColorDisplayManager.setReduceBrightColorsActivated(enabled);
|
||||
}
|
||||
|
||||
@@ -161,8 +168,8 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.reduce_bright_colors_shortcut_title);
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getText(R.string.reduce_bright_colors_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,6 +178,18 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
|
||||
mComponentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
ComponentName getTileComponentName() {
|
||||
return REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
|
||||
return getText(type == QuickSettingsTooltipType.GUIDE_TO_EDIT
|
||||
? R.string.accessibility_reduce_bright_colors_qs_tooltip_content
|
||||
: R.string.accessibility_reduce_bright_colors_auto_added_qs_tooltip_content);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSwitchBarToggleSwitch() {
|
||||
final boolean checked = mColorDisplayManager.isReduceBrightColorsActivated();
|
||||
|
||||
@@ -23,9 +23,11 @@ import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.icu.text.CaseMap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -40,11 +42,13 @@ import android.widget.CheckBox;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.DialogCreatable;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||
import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
|
||||
import com.android.settings.utils.LocaleUtils;
|
||||
|
||||
@@ -73,8 +77,10 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
|
||||
new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
|
||||
|
||||
private MagnificationModePreferenceController mModePreferenceController;
|
||||
private DialogCreatable mDialogDelegate;
|
||||
private MagnificationFollowTypingPreferenceController mFollowTypingPreferenceController;
|
||||
|
||||
protected SwitchPreference mFollowingTypingSwitchPreference;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -103,10 +109,10 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
private void updateFooterPreference() {
|
||||
final String title = getPrefContext().getString(
|
||||
R.string.accessibility_screen_magnification_about_title);
|
||||
final String learnMoreContentDescription = getPrefContext().getString(
|
||||
final String learnMoreText = getPrefContext().getString(
|
||||
R.string.accessibility_screen_magnification_footer_learn_more_content_description);
|
||||
mFooterPreferenceController.setIntroductionTitle(title);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreContentDescription);
|
||||
mFooterPreferenceController.setupHelpLink(getHelpResource(), learnMoreText);
|
||||
mFooterPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
@@ -141,8 +147,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
return AccessibilityGestureNavigationTutorial
|
||||
.showAccessibilityGestureTutorialDialog(getPrefContext());
|
||||
case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT:
|
||||
final CharSequence dialogTitle = getPrefContext().getString(
|
||||
R.string.accessibility_shortcut_title, mPackageName);
|
||||
final CharSequence dialogTitle = getShortcutTitle();
|
||||
final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent())
|
||||
? DialogType.EDIT_SHORTCUT_MAGNIFICATION_SUW
|
||||
: DialogType.EDIT_SHORTCUT_MAGNIFICATION;
|
||||
@@ -157,9 +162,14 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
|
||||
@Override
|
||||
protected void initSettingsPreference() {
|
||||
// If the device doesn't support magnification area, it should hide the settings preference.
|
||||
if (!getContext().getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_magnification_area)) {
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
mSettingsPreference = new Preference(getPrefContext());
|
||||
@@ -170,11 +180,27 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
|
||||
generalCategory.addPreference(mSettingsPreference);
|
||||
|
||||
mModePreferenceController = new MagnificationModePreferenceController(getContext(),
|
||||
MagnificationModePreferenceController.PREF_KEY);
|
||||
mModePreferenceController.setDialogHelper(this);
|
||||
getSettingsLifecycle().addObserver(mModePreferenceController);
|
||||
mModePreferenceController.displayPreference(getPreferenceScreen());
|
||||
final MagnificationModePreferenceController magnificationModePreferenceController =
|
||||
new MagnificationModePreferenceController(getContext(),
|
||||
MagnificationModePreferenceController.PREF_KEY);
|
||||
magnificationModePreferenceController.setDialogHelper(this);
|
||||
getSettingsLifecycle().addObserver(magnificationModePreferenceController);
|
||||
magnificationModePreferenceController.displayPreference(getPreferenceScreen());
|
||||
|
||||
mFollowingTypingSwitchPreference =
|
||||
new SwitchPreference(getPrefContext());
|
||||
mFollowingTypingSwitchPreference.setTitle(
|
||||
R.string.accessibility_screen_magnification_follow_typing_title);
|
||||
mFollowingTypingSwitchPreference.setSummary(
|
||||
R.string.accessibility_screen_magnification_follow_typing_summary);
|
||||
mFollowingTypingSwitchPreference.setKey(
|
||||
MagnificationFollowTypingPreferenceController.PREF_KEY);
|
||||
generalCategory.addPreference(mFollowingTypingSwitchPreference);
|
||||
|
||||
mFollowTypingPreferenceController = new MagnificationFollowTypingPreferenceController(
|
||||
getContext(), MagnificationFollowTypingPreferenceController.PREF_KEY);
|
||||
getSettingsLifecycle().addObserver(mFollowTypingPreferenceController);
|
||||
mFollowTypingPreferenceController.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -276,8 +302,23 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getFeatureSettingsKeys() {
|
||||
final List<String> shortcutKeys = super.getFeatureSettingsKeys();
|
||||
protected void registerKeysToObserverCallback(
|
||||
AccessibilitySettingsContentObserver contentObserver) {
|
||||
super.registerKeysToObserverCallback(contentObserver);
|
||||
|
||||
final List<String> followingTypingKeys = new ArrayList<>();
|
||||
followingTypingKeys.add(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED);
|
||||
contentObserver.registerKeysToObserverCallback(followingTypingKeys,
|
||||
key -> updateFollowTypingState());
|
||||
}
|
||||
|
||||
private void updateFollowTypingState() {
|
||||
mFollowTypingPreferenceController.updateState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getShortcutFeatureSettingsKeys() {
|
||||
final List<String> shortcutKeys = super.getShortcutFeatureSettingsKeys();
|
||||
shortcutKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
|
||||
return shortcutKeys;
|
||||
}
|
||||
@@ -325,6 +366,10 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
mShortcutPreference.setChecked(value != UserShortcutType.EMPTY);
|
||||
mShortcutPreference.setSummary(
|
||||
getShortcutTypeSummary(getPrefContext()));
|
||||
|
||||
if (mHardwareTypeCheckBox.isChecked()) {
|
||||
AccessibilityUtil.skipVolumeShortcutDialogTimeoutRestriction(getPrefContext());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -364,6 +409,16 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
return getUserShortcutTypeFromSettings(getPrefContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
ComponentName getTileComponentName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
||||
if (enabled && TextUtils.equals(
|
||||
@@ -414,17 +469,15 @@ public class ToggleScreenMagnificationPreferenceFragment extends
|
||||
mShortcutPreference.setKey(getShortcutPreferenceKey());
|
||||
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
|
||||
mShortcutPreference.setOnClickCallback(this);
|
||||
|
||||
final CharSequence title = getString(R.string.accessibility_shortcut_title, mPackageName);
|
||||
mShortcutPreference.setTitle(title);
|
||||
mShortcutPreference.setTitle(getShortcutTitle());
|
||||
|
||||
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
|
||||
generalCategory.addPreference(mShortcutPreference);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShortcutTitle(ShortcutPreference shortcutPreference) {
|
||||
shortcutPreference.setTitle(R.string.accessibility_screen_magnification_shortcut_title);
|
||||
protected CharSequence getShortcutTitle() {
|
||||
return getText(R.string.accessibility_screen_magnification_shortcut_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user