diff --git a/res/layout/edit_user_info_dialog_content.xml b/res/layout/edit_user_info_dialog_content.xml index 62c711b789e..895cef63fb9 100644 --- a/res/layout/edit_user_info_dialog_content.xml +++ b/res/layout/edit_user_info_dialog_content.xml @@ -42,7 +42,6 @@ android:singleLine="true" android:textAppearance="?android:attr/textAppearanceMedium" android:textAlignment="viewStart" - android:labelFor="@id/user_photo" android:inputType="text|textCapWords" android:selectAllOnFocus="true" android:hint="@string/user_nickname" diff --git a/res/layout/notification_history_log_row.xml b/res/layout/notification_history_log_row.xml index 4f45fecd0ae..04438e33f61 100644 --- a/res/layout/notification_history_log_row.xml +++ b/res/layout/notification_history_log_row.xml @@ -76,7 +76,7 @@ android:layout_height="wrap_content" android:layout_gravity="left|center_vertical" android:ellipsize="end" - android:singleLine="true" + android:maxLines="3" android:paddingTop="3dp" android:textAppearance="@style/TextAppearance.NotificationHistory.Text" android:textAlignment="viewStart" /> diff --git a/res/layout/notification_sbn_log_row.xml b/res/layout/notification_sbn_log_row.xml index a5b8dd0fde7..7a3e6d7d817 100644 --- a/res/layout/notification_sbn_log_row.xml +++ b/res/layout/notification_sbn_log_row.xml @@ -125,7 +125,7 @@ android:layout_height="wrap_content" android:layout_gravity="left|center_vertical" android:ellipsize="end" - android:singleLine="true" + android:maxLines="3" android:textAppearance="@style/TextAppearance.NotificationHistory.Text" android:textAlignment="viewStart" /> diff --git a/res/values/strings.xml b/res/values/strings.xml index 812ff86e20e..5ba2b7a2c79 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7323,7 +7323,7 @@ Send & receive when mobile data is off - com.android.cellbroadcastreceiver + com.android.cellbroadcastreceiver.module + - - diff --git a/res/xml/notification_access_permission_details.xml b/res/xml/notification_access_permission_details.xml index 8cc5993904f..d956ce911ac 100644 --- a/res/xml/notification_access_permission_details.xml +++ b/res/xml/notification_access_permission_details.xml @@ -20,7 +20,7 @@ android:key="notification_access_permission_detail_settings" android:title="@string/manage_notification_access_title"> - diff --git a/res/xml/picture_in_picture_permissions_details.xml b/res/xml/picture_in_picture_permissions_details.xml index c215c9d9cf7..5f2a45ae55c 100644 --- a/res/xml/picture_in_picture_permissions_details.xml +++ b/res/xml/picture_in_picture_permissions_details.xml @@ -18,7 +18,7 @@ android:key="picture_in_picture_permission_detail_settings" android:title="@string/picture_in_picture_app_detail_title"> - diff --git a/res/xml/write_system_settings_permissions_details.xml b/res/xml/write_system_settings_permissions_details.xml index 82a6931592c..21ea7065e1b 100644 --- a/res/xml/write_system_settings_permissions_details.xml +++ b/res/xml/write_system_settings_permissions_details.xml @@ -18,7 +18,7 @@ android:key="write_system_settings_permission_detail_settings" android:title="@string/write_settings"> - diff --git a/res/xml/zen_access_permission_details.xml b/res/xml/zen_access_permission_details.xml index afa8d80a17c..de014d1c6bd 100644 --- a/res/xml/zen_access_permission_details.xml +++ b/res/xml/zen_access_permission_details.xml @@ -20,7 +20,7 @@ android:key="zen_access_permission_detail_settings" android:title="@string/manage_zen_access_title"> - diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index 69f65a47316..5ef12329a54 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -119,7 +119,6 @@ import com.android.settings.widget.LoadingViewController; import com.android.settings.wifi.AppStateChangeWifiStateBridge; import com.android.settings.wifi.ChangeWifiStateDetails; import com.android.settingslib.HelpUtils; -import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; @@ -1462,12 +1461,10 @@ public class ManageApplications extends InstrumentedFragment ApplicationsState.AppEntry entry = mEntries.get(position); synchronized (entry) { holder.setTitle(entry.label); - holder.itemView.setContentDescription( - AppUtils.getAppContentDescription( - mContext, - entry.info.packageName, - UserHandle.getUserId(entry.info.uid))); - holder.setIcon(Utils.getBadgedIcon(mContext, entry.info)); + mState.ensureLabelDescription(entry); + holder.itemView.setContentDescription(entry.labelDescription); + mState.ensureIcon(entry); + holder.setIcon(entry.icon); updateSummary(holder, entry); updateSwitch(holder, entry); holder.updateDisableView(entry.info); diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java index d8ec8489cd4..e25bb1e4fc0 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminListPreferenceController.java @@ -43,10 +43,10 @@ import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; import com.android.settings.core.BasePreferenceController; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.widget.FilterTouchesSwitchPreference; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; @@ -168,32 +168,32 @@ public class DeviceAdminListPreferenceController extends BasePreferenceControlle if (mFooterPreference != null) { mFooterPreference.setVisible(mAdmins.isEmpty()); } - final Map preferenceCache = new ArrayMap<>(); + final Map preferenceCache = new ArrayMap<>(); final Context prefContext = mPreferenceGroup.getContext(); final int childrenCount = mPreferenceGroup.getPreferenceCount(); for (int i = 0; i < childrenCount; i++) { final Preference pref = mPreferenceGroup.getPreference(i); - if (!(pref instanceof SwitchPreference)) { + if (!(pref instanceof FilterTouchesSwitchPreference)) { continue; } - final SwitchPreference appSwitch = (SwitchPreference) pref; + final FilterTouchesSwitchPreference appSwitch = (FilterTouchesSwitchPreference) pref; preferenceCache.put(appSwitch.getKey(), appSwitch); } for (DeviceAdminListItem item : mAdmins) { final String key = item.getKey(); - SwitchPreference pref = preferenceCache.remove(key); + FilterTouchesSwitchPreference pref = preferenceCache.remove(key); if (pref == null) { - pref = new SwitchPreference(prefContext); + pref = new FilterTouchesSwitchPreference(prefContext); mPreferenceGroup.addPreference(pref); } bindPreference(item, pref); } - for (SwitchPreference unusedCacheItem : preferenceCache.values()) { + for (FilterTouchesSwitchPreference unusedCacheItem : preferenceCache.values()) { mPreferenceGroup.removePreference(unusedCacheItem); } } - private void bindPreference(DeviceAdminListItem item, SwitchPreference pref) { + private void bindPreference(DeviceAdminListItem item, FilterTouchesSwitchPreference pref) { pref.setKey(item.getKey()); pref.setTitle(item.getName()); pref.setIcon(item.getIcon()); diff --git a/src/com/android/settings/aware/AwareFeatureProvider.java b/src/com/android/settings/aware/AwareFeatureProvider.java index bda27c7143c..a4e9c0cd31d 100644 --- a/src/com/android/settings/aware/AwareFeatureProvider.java +++ b/src/com/android/settings/aware/AwareFeatureProvider.java @@ -29,4 +29,8 @@ public interface AwareFeatureProvider { /** Show information dialog. */ void showRestrictionDialog(Fragment parent); + + /** Return Quick Gestures Summary. */ + CharSequence getGestureSummary(Context context, boolean sensorSupported, + boolean assistGestureEnabled, boolean assistGestureSilenceEnabled); } diff --git a/src/com/android/settings/aware/AwareFeatureProviderImpl.java b/src/com/android/settings/aware/AwareFeatureProviderImpl.java index 5d160313869..6f80d8a7ae5 100644 --- a/src/com/android/settings/aware/AwareFeatureProviderImpl.java +++ b/src/com/android/settings/aware/AwareFeatureProviderImpl.java @@ -34,4 +34,10 @@ public class AwareFeatureProviderImpl implements AwareFeatureProvider { @Override public void showRestrictionDialog(Fragment parent) { } + + @Override + public CharSequence getGestureSummary(Context context, boolean sensorSupported, + boolean assistGestureEnabled, boolean assistGestureSilenceEnabled) { + return null; + } } diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java index f71949455d1..f8a4f39ef77 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -125,5 +125,9 @@ public class DashboardFragmentRegistry { for (Map.Entry parentToKey : PARENT_TO_CATEGORY_KEY_MAP.entrySet()) { CATEGORY_KEY_TO_PARENT_MAP.put(parentToKey.getValue(), parentToKey.getKey()); } + + // For injection index, redirect CATEGORY_ACCOUNT_DETAIL to AccountDashboardFragment. + CATEGORY_KEY_TO_PARENT_MAP.put(CategoryKey.CATEGORY_ACCOUNT_DETAIL, + AccountDashboardFragment.class.getName()); } } diff --git a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java index 98eddffb8fa..9d4d538f426 100644 --- a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java +++ b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java @@ -20,10 +20,12 @@ import android.content.ContentResolver; import android.content.Context; import android.hardware.display.AmbientDisplayConfiguration; import android.provider.Settings; +import android.text.TextUtils; import androidx.annotation.NonNull; import com.android.settings.R; +import com.android.settings.aware.AwareFeatureProvider; import com.android.settings.core.BasePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; @@ -33,6 +35,7 @@ import java.util.List; public class GesturesSettingPreferenceController extends BasePreferenceController { private final AssistGestureFeatureProvider mFeatureProvider; + private final AwareFeatureProvider mAwareFeatureProvider; private List mGestureControllers; private static final String KEY_GESTURES_SETTINGS = "gesture_settings"; @@ -41,6 +44,7 @@ public class GesturesSettingPreferenceController extends BasePreferenceControlle public GesturesSettingPreferenceController(Context context) { super(context, KEY_GESTURES_SETTINGS); mFeatureProvider = FeatureFactory.getFactory(context).getAssistGestureFeatureProvider(); + mAwareFeatureProvider = FeatureFactory.getFactory(context).getAwareFeatureProvider(); } @Override @@ -90,8 +94,15 @@ public class GesturesSettingPreferenceController extends BasePreferenceControlle contentResolver, Settings.Secure.ASSIST_GESTURE_ENABLED, 1) != 0; final boolean assistGestureSilenceEnabled = Settings.Secure.getInt( contentResolver, Settings.Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, 1) != 0; + final boolean sensorSupported = mFeatureProvider.isSupported(mContext); - if (mFeatureProvider.isSupported(mContext) && assistGestureEnabled) { + final CharSequence awareSummary = mAwareFeatureProvider.getGestureSummary(mContext, + sensorSupported, assistGestureEnabled, assistGestureSilenceEnabled); + if (!TextUtils.isEmpty(awareSummary)) { + return awareSummary; + } + + if (sensorSupported && assistGestureEnabled) { return mContext.getText( R.string.language_input_gesture_summary_on_with_assist); } diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java index 719d2d5641d..1288cf51c0b 100644 --- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java +++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java @@ -176,9 +176,13 @@ public class MediaDeviceUpdateWorker extends SliceBackgroundWorker return mLocalMediaManager.getSelectedMediaDevice(); } - boolean isSelectedMediaDevice(MediaDevice device) { - for (MediaDevice selectedMediaDevice : getSelectedMediaDevice()) { - if (TextUtils.equals(selectedMediaDevice.getId(), device.getId())) { + List getDeselectableMediaDevice() { + return mLocalMediaManager.getDeselectableMediaDevice(); + } + + boolean isDeviceIncluded(Collection deviceCollection, MediaDevice targetDevice) { + for (MediaDevice device : deviceCollection) { + if (TextUtils.equals(device.getId(), targetDevice.getId())) { return true; } } diff --git a/src/com/android/settings/media/MediaOutputGroupSlice.java b/src/com/android/settings/media/MediaOutputGroupSlice.java index ba29ab73c87..d33ca45a812 100644 --- a/src/com/android/settings/media/MediaOutputGroupSlice.java +++ b/src/com/android/settings/media/MediaOutputGroupSlice.java @@ -43,6 +43,7 @@ import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.slices.SliceBroadcastReceiver; import com.android.settingslib.media.MediaDevice; +import java.util.ArrayList; import java.util.List; /** @@ -122,6 +123,10 @@ public class MediaOutputGroupSlice implements CustomSliceable { private void addRow(ListBuilder listBuilder, List mediaDevices, boolean selected) { final boolean adjustVolumeUserRestriction = getWorker().hasAdjustVolumeUserRestriction(); + List deselectableMediaDevices = new ArrayList<>(); + if (selected) { + deselectableMediaDevices = getWorker().getDeselectableMediaDevice(); + } for (MediaDevice device : mediaDevices) { final int maxVolume = device.getMaxVolume(); final IconCompat titleIcon = Utils.createIconWithDrawable(device.getIcon()); @@ -147,7 +152,8 @@ public class MediaOutputGroupSlice implements CustomSliceable { .setMax(device.getMaxVolume()) .setValue(device.getCurrentVolume()); // Add endItem with different icons - if (mediaDevices.size() == 1 && selected) { + if (selected && (!getWorker().isDeviceIncluded(deselectableMediaDevices, device) + || mediaDevices.size() == 1)) { builder.addEndItem(disabledIconSliceAction); } else { builder.addEndItem(enabledIconSliceAction); @@ -158,7 +164,8 @@ public class MediaOutputGroupSlice implements CustomSliceable { .setTitleItem(titleIcon, ListBuilder.ICON_IMAGE) .setTitle(title); // Add endItem with different icons - if (mediaDevices.size() == 1 && selected) { + if (selected && (!getWorker().isDeviceIncluded(deselectableMediaDevices, device) + || mediaDevices.size() == 1)) { rowBuilder.addEndItem(disabledIconSliceAction); } else { rowBuilder.addEndItem(enabledIconSliceAction); @@ -209,7 +216,8 @@ public class MediaOutputGroupSlice implements CustomSliceable { Log.e(TAG, "Unable to handle notification. The device is unavailable"); return; } - final MediaDevice device = getWorker().getMediaDeviceById(id); + final MediaDeviceUpdateWorker worker = getWorker(); + final MediaDevice device = worker.getMediaDeviceById(id); switch (intent.getIntExtra(CUSTOMIZED_ACTION, ERROR)) { case ACTION_VOLUME_ADJUSTMENT: final int newPosition = intent.getIntExtra(EXTRA_RANGE_VALUE, ERROR); @@ -219,7 +227,7 @@ public class MediaOutputGroupSlice implements CustomSliceable { } // Group volume adjustment if (TextUtils.equals(id, GROUP_DEVICES)) { - getWorker().adjustSessionVolume(newPosition); + worker.adjustSessionVolume(newPosition); } else { if (device == null) { Log.e(TAG, "Unable to adjust volume. The device(" + id @@ -227,7 +235,7 @@ public class MediaOutputGroupSlice implements CustomSliceable { return; } // Single device volume adjustment - getWorker().adjustVolume(device, newPosition); + worker.adjustVolume(device, newPosition); } break; case ACTION_MEDIA_SESSION_OPERATION: @@ -236,10 +244,13 @@ public class MediaOutputGroupSlice implements CustomSliceable { + ") is unavailable"); return; } - if (getWorker().isSelectedMediaDevice(device)) { - getWorker().removeDeviceFromPlayMedia(device); + if (worker.isDeviceIncluded(worker.getSelectableMediaDevice(), device)) { + worker.addDeviceToPlayMedia(device); + } else if (worker.isDeviceIncluded(worker.getDeselectableMediaDevice(), device)) { + worker.removeDeviceFromPlayMedia(device); } else { - getWorker().addDeviceToPlayMedia(device); + // Do nothing + Log.d(TAG, device.getName() + " is not selectable nor deselectable"); } break; } diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java index a498d474f83..46c5234e4a5 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java @@ -75,13 +75,14 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl mSwitchBar.setSwitchBarText(R.string.mobile_network_use_sim_on, R.string.mobile_network_use_sim_off); - mSwitchBar.addOnSwitchChangeListener((switchView, isChecked) -> { + mSwitchBar.getSwitch().setOnBeforeCheckedChangeListener((toggleSwitch, isChecked) -> { // TODO b/135222940: re-evaluate whether to use // mSubscriptionManager#isSubscriptionEnabled if (mSubscriptionManager.isActiveSubscriptionId(mSubId) != isChecked && (!mSubscriptionManager.setSubscriptionEnabled(mSubId, isChecked))) { - mSwitchBar.setChecked(!isChecked); + return true; } + return false; }); update(); } @@ -106,7 +107,7 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl mSwitchBar.hide(); } else { mSwitchBar.show(); - mSwitchBar.setChecked(mSubscriptionManager.isActiveSubscriptionId(mSubId)); + mSwitchBar.setCheckedInternal(mSubscriptionManager.isActiveSubscriptionId(mSubId)); } } diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index 1e5e21e4919..525ac84e3c4 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -140,7 +140,15 @@ public class NotificationHistoryActivity extends Activity { final NotificationHistoryRecyclerView rv = viewForPackage.findViewById(R.id.notification_list); - rv.setAdapter(new NotificationHistoryAdapter(mNm, rv)); + rv.setAdapter(new NotificationHistoryAdapter(mNm, rv, + newCount -> { + count.setText(getResources().getQuantityString( + R.plurals.notification_history_count, + newCount, newCount)); + if (newCount == 0) { + viewForPackage.setVisibility(View.GONE); + } + })); ((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete( new ArrayList<>(nhp.notifications)); diff --git a/src/com/android/settings/notification/history/NotificationHistoryAdapter.java b/src/com/android/settings/notification/history/NotificationHistoryAdapter.java index 4a5c627eb28..70eee21e985 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryAdapter.java +++ b/src/com/android/settings/notification/history/NotificationHistoryAdapter.java @@ -49,13 +49,16 @@ public class NotificationHistoryAdapter extends private INotificationManager mNm; private List mValues; + private OnItemDeletedListener mListener; public NotificationHistoryAdapter(INotificationManager nm, - NotificationHistoryRecyclerView listView) { + NotificationHistoryRecyclerView listView, + OnItemDeletedListener listener) { mValues = new ArrayList<>(); setHasStableIds(true); listView.setOnItemSwipeDeleteListener(this); mNm = nm; + mListener = listener; } @Override @@ -134,6 +137,11 @@ public class NotificationHistoryAdapter extends Slog.e(TAG, "Failed to delete item", e); } } + mListener.onItemDeleted(mValues.size()); notifyItemRemoved(position); } + + interface OnItemDeletedListener { + void onItemDeleted(int newCount); + } } diff --git a/src/com/android/settings/notification/history/NotificationSbnAdapter.java b/src/com/android/settings/notification/history/NotificationSbnAdapter.java index 27ecabdd92e..def98de6b9c 100644 --- a/src/com/android/settings/notification/history/NotificationSbnAdapter.java +++ b/src/com/android/settings/notification/history/NotificationSbnAdapter.java @@ -20,12 +20,16 @@ import static android.app.Notification.COLOR_DEFAULT; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.content.pm.PackageManager.NameNotFoundException; import static android.os.UserHandle.USER_ALL; +import static android.provider.Settings.EXTRA_APP_PACKAGE; +import static android.provider.Settings.EXTRA_CHANNEL_ID; +import static android.provider.Settings.EXTRA_CONVERSATION_ID; import android.annotation.ColorInt; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.Notification; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -33,6 +37,7 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Log; @@ -113,6 +118,15 @@ public class NotificationSbnAdapter extends holder.setProfileBadge(mUserBadgeCache.get(userId)); holder.addOnClick(sbn.getPackageName(), sbn.getUserId(), sbn.getNotification().contentIntent); + holder.itemView.setOnLongClickListener(v -> { + Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) + .putExtra(EXTRA_APP_PACKAGE, sbn.getPackageName()) + .putExtra(EXTRA_CHANNEL_ID, sbn.getNotification().getChannelId()) + .putExtra(EXTRA_CONVERSATION_ID, sbn.getNotification().getShortcutId()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + holder.itemView.getContext().startActivityAsUser(intent, UserHandle.of(userId)); + return true; + }); } else { Slog.w(TAG, "null entry in list at position " + position); } diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index 3c81eb8e0c3..64812fdd627 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -107,6 +107,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { private int mUserId; private int mCredentialMode; private boolean mGoingToBackground; + private boolean mWaitingForBiometricCallback; private Executor mExecutor = (runnable -> { mHandler.post(runnable); @@ -116,6 +117,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { @Override public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { if (!mGoingToBackground) { + mWaitingForBiometricCallback = false; if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED || errorCode == BiometricPrompt.BIOMETRIC_ERROR_CANCELED) { finish(); @@ -123,11 +125,15 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { // All other errors go to some version of CC showConfirmCredentials(); } + } else if (mWaitingForBiometricCallback) { // mGoingToBackground is true + mWaitingForBiometricCallback = false; + finish(); } } @Override public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) { + mWaitingForBiometricCallback = false; mTrustManager.setDeviceLockedForUser(mUserId, false); final boolean isStrongAuth = result.getAuthenticationType() == BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL; @@ -142,6 +148,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { @Override public void onAuthenticationFailed() { + mWaitingForBiometricCallback = false; mDevicePolicyManager.reportFailedBiometricAttempt(mUserId); } @@ -262,6 +269,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { finish(); } else if (launchedBiometric) { // Keep this activity alive until BiometricPrompt goes away + mWaitingForBiometricCallback = true; } else { Log.d(TAG, "No pattern, password or PIN set."); setResult(Activity.RESULT_OK); @@ -320,7 +328,9 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { super.onPause(); if (!isChangingConfigurations()) { mGoingToBackground = true; - finish(); + if (!mWaitingForBiometricCallback) { + finish(); + } } else { mGoingToBackground = false; } diff --git a/src/com/android/settings/users/MultiUserSwitchBarController.java b/src/com/android/settings/users/MultiUserSwitchBarController.java index a5fdf9b3279..58de14963fa 100644 --- a/src/com/android/settings/users/MultiUserSwitchBarController.java +++ b/src/com/android/settings/users/MultiUserSwitchBarController.java @@ -52,8 +52,6 @@ public class MultiUserSwitchBarController implements SwitchWidgetController.OnSw mListener = listener; mUserCapabilities = UserCapabilities.create(context); mSwitchBar.setChecked(mUserCapabilities.mUserSwitcherEnabled); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.USER_SWITCHER_ENABLED, mSwitchBar.isChecked() ? 1 : 0); if (mUserCapabilities.mDisallowSwitchUser) { mSwitchBar.setDisabledByAdmin(RestrictedLockUtilsInternal diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java index 4e6cc893b8e..12d91ec2042 100644 --- a/src/com/android/settings/vpn2/ConfigDialog.java +++ b/src/com/android/settings/vpn2/ConfigDialog.java @@ -20,6 +20,7 @@ import static com.android.internal.net.VpnProfile.isLegacyType; import android.content.Context; import android.content.DialogInterface; +import android.content.pm.PackageManager; import android.net.Proxy; import android.net.ProxyInfo; import android.os.Bundle; @@ -43,6 +44,9 @@ import com.android.internal.net.VpnProfile; import com.android.settings.R; import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * Dialog showing information about a VPN configuration. The dialog @@ -129,6 +133,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // Second, copy values from the profile. mName.setText(mProfile.name); + setTypesByFeature(mType); mType.setSelection(mProfile.type); mServer.setText(mProfile.server); if (mProfile.saveLogin) { @@ -487,6 +492,25 @@ class ConfigDialog extends AlertDialog implements TextWatcher, return true; } + private void setTypesByFeature(Spinner typeSpinner) { + String[] types = getContext().getResources().getStringArray(R.array.vpn_types); + if (!getContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_IPSEC_TUNNELS)) { + final List typesList = new ArrayList<>(Arrays.asList(types)); + + // This must be removed from back to front in order to ensure index consistency + typesList.remove(VpnProfile.TYPE_IKEV2_IPSEC_RSA); + typesList.remove(VpnProfile.TYPE_IKEV2_IPSEC_PSK); + typesList.remove(VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS); + + types = typesList.toArray(new String[0]); + } + final ArrayAdapter adapter = new ArrayAdapter( + getContext(), android.R.layout.simple_spinner_item, types); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + typeSpinner.setAdapter(adapter); + } + private void loadCertificates(Spinner spinner, String prefix, int firstId, String selected) { Context context = getContext(); String first = (firstId == 0) ? "" : context.getString(firstId); diff --git a/src/com/android/settings/widget/AppSwitchPreference.java b/src/com/android/settings/widget/AppSwitchPreference.java index 506ab7642ae..90f1dbd0782 100644 --- a/src/com/android/settings/widget/AppSwitchPreference.java +++ b/src/com/android/settings/widget/AppSwitchPreference.java @@ -17,7 +17,9 @@ package com.android.settings.widget; import android.content.Context; +import android.view.View; +import androidx.preference.PreferenceViewHolder; import androidx.preference.SwitchPreference; import com.android.settings.R; @@ -28,4 +30,13 @@ public class AppSwitchPreference extends SwitchPreference { super(context); setLayoutResource(R.layout.preference_app); } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + final View switchView = holder.findViewById(android.R.id.switch_widget); + if (switchView != null) { + switchView.setFilterTouchesWhenObscured(true); + } + } } diff --git a/src/com/android/settings/widget/FilterTouchesRestrictedSwitchPreference.java b/src/com/android/settings/widget/FilterTouchesRestrictedSwitchPreference.java new file mode 100644 index 00000000000..c5e0217dd0f --- /dev/null +++ b/src/com/android/settings/widget/FilterTouchesRestrictedSwitchPreference.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +import androidx.preference.PreferenceViewHolder; + +import com.android.settingslib.RestrictedSwitchPreference; + +/** + * This widget with enabled filterTouchesWhenObscured attribute use to replace + * the {@link RestrictedSwitchPreference} in the Special access app pages for + * security. + */ +public class FilterTouchesRestrictedSwitchPreference extends RestrictedSwitchPreference { + public FilterTouchesRestrictedSwitchPreference(Context context, AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public FilterTouchesRestrictedSwitchPreference(Context context, AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public FilterTouchesRestrictedSwitchPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FilterTouchesRestrictedSwitchPreference(Context context) { + super(context); + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + final View switchView = holder.findViewById(android.R.id.switch_widget); + if (switchView != null) { + switchView.setFilterTouchesWhenObscured(true); + } + } +} diff --git a/src/com/android/settings/widget/FilterTouchesSwitchPreference.java b/src/com/android/settings/widget/FilterTouchesSwitchPreference.java new file mode 100644 index 00000000000..a4e3c6e76da --- /dev/null +++ b/src/com/android/settings/widget/FilterTouchesSwitchPreference.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +import androidx.preference.PreferenceViewHolder; +import androidx.preference.SwitchPreference; + +/** + * This widget with enabled filterTouchesWhenObscured attribute use to replace + * the {@link SwitchPreference} in the Special access app pages for security. + */ +public class FilterTouchesSwitchPreference extends SwitchPreference { + + public FilterTouchesSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public FilterTouchesSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public FilterTouchesSwitchPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FilterTouchesSwitchPreference(Context context) { + super(context); + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + final View switchView = holder.findViewById(android.R.id.switch_widget); + if (switchView != null) { + switchView.setFilterTouchesWhenObscured(true); + } + } +} diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentRegistryTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentRegistryTest.java index c6b24658dbd..10aaad8b2f0 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentRegistryTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentRegistryTest.java @@ -18,6 +18,9 @@ package com.android.settings.dashboard; import static com.google.common.truth.Truth.assertThat; +import com.android.settings.accounts.AccountDashboardFragment; +import com.android.settingslib.drawer.CategoryKey; + import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -29,4 +32,12 @@ public class DashboardFragmentRegistryTest { assertThat(DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP.size()) .isEqualTo(DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP.size()); } + + @Test + public void accountDetailCategoryShouldRedirectToAccountDashboardFragment() { + final String fragment = DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP.get( + CategoryKey.CATEGORY_ACCOUNT_DETAIL); + + assertThat(fragment).isEqualTo(AccountDashboardFragment.class.getName()); + } } diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java index 9da18d50cde..bb0478cc8b7 100644 --- a/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java +++ b/tests/robotests/src/com/android/settings/media/MediaOutputGroupSliceTest.java @@ -90,6 +90,7 @@ public class MediaOutputGroupSliceTest { private final List mSelectableDevices = new ArrayList<>(); private final List mSelectedDevices = new ArrayList<>(); + private final List mDeselectableDevices = new ArrayList<>(); private Context mContext; private MediaOutputGroupSlice mMediaOutputGroupSlice; @@ -227,14 +228,19 @@ public class MediaOutputGroupSliceTest { verify(sMediaDeviceUpdateWorker).addDeviceToPlayMedia(mDevice2); } + @Test - public void onNotifyChange_sendSelectedDevice_verifyRemoveSession() { + public void onNotifyChange_sendDeselectableDevice_verifyRemoveSession() { mSelectedDevices.add(mDevice1); mSelectedDevices.add(mDevice2); + mDeselectableDevices.add(mDevice1); + mDeselectableDevices.add(mDevice2); when(mLocalMediaManager.getMediaDeviceById(mSelectedDevices, TEST_DEVICE_2_ID)) .thenReturn(mDevice2); sMediaDeviceUpdateWorker.onDeviceListUpdate(mSelectedDevices); when(sMediaDeviceUpdateWorker.getSelectedMediaDevice()).thenReturn(mSelectedDevices); + when(sMediaDeviceUpdateWorker.getDeselectableMediaDevice()).thenReturn( + mDeselectableDevices); final Intent intent = new Intent(); intent.putExtra(MEDIA_DEVICE_ID, TEST_DEVICE_2_ID); intent.putExtra(CUSTOMIZED_ACTION, ACTION_MEDIA_SESSION_OPERATION); @@ -244,6 +250,26 @@ public class MediaOutputGroupSliceTest { verify(sMediaDeviceUpdateWorker).removeDeviceFromPlayMedia(mDevice2); } + @Test + public void onNotifyChange_sendNonDeselectableDevice_notRemoveSession() { + mSelectedDevices.add(mDevice1); + mSelectedDevices.add(mDevice2); + mDeselectableDevices.add(mDevice1); + when(mLocalMediaManager.getMediaDeviceById(mSelectedDevices, TEST_DEVICE_2_ID)) + .thenReturn(mDevice2); + sMediaDeviceUpdateWorker.onDeviceListUpdate(mSelectedDevices); + when(sMediaDeviceUpdateWorker.getSelectedMediaDevice()).thenReturn(mSelectedDevices); + when(sMediaDeviceUpdateWorker.getDeselectableMediaDevice()).thenReturn( + mDeselectableDevices); + final Intent intent = new Intent(); + intent.putExtra(MEDIA_DEVICE_ID, TEST_DEVICE_2_ID); + intent.putExtra(CUSTOMIZED_ACTION, ACTION_MEDIA_SESSION_OPERATION); + + mMediaOutputGroupSlice.onNotifyChange(intent); + + verify(sMediaDeviceUpdateWorker, never()).removeDeviceFromPlayMedia(mDevice2); + } + @Test public void onNotifyChange_noId_doNothing() { mSelectableDevices.add(mDevice1);