Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5c651b9..4f12b79 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7163,15 +7163,13 @@
<!-- Title for Guest user [CHAR LIMIT=35] -->
<string name="user_guest">Guest</string>
<!-- Label for item to exit guest mode [CHAR LIMIT=35] -->
- <string name="user_clear_guest_menu">Clear guest data</string>
- <!-- Label for item to exit guest mode [CHAR LIMIT=35] -->
- <string name="user_exit_guest_menu">End guest session</string>
+ <string name="user_exit_guest_title">Remove guest</string>
<!-- Title of dialog to user to confirm exiting guest. [CHAR LIMIT=50] -->
- <string name="user_exit_guest_confirm_title">End guest session?</string>
+ <string name="user_exit_guest_confirm_title">Remove guest?</string>
<!-- Message to user to confirm exiting guest. [CHAR LIMIT=none] -->
<string name="user_exit_guest_confirm_message">All apps and data in this session will be deleted.</string>
<!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
- <string name="user_exit_guest_dialog_remove">End session</string>
+ <string name="user_exit_guest_dialog_remove">Remove</string>
<!-- Title of preference to enable calling[CHAR LIMIT=40] -->
<string name="user_enable_calling">Turn on phone calls</string>
@@ -8820,6 +8818,22 @@
<string name="notif_type_alerting">Alerting notifications</string>
<string name="notif_type_silent">Silent notifications</string>
+ <!-- Per notification listener, launches a list of apps whose notifications this listener cannot see -->
+ <string name="notif_listener_excluded_title">Apps that are not bridged to this listener</string>
+
+ <!-- Per notification listener, when the listener can see notifications from all apps -->
+ <string name="notif_listener_excluded_summary_zero">All apps are bridged</string>
+
+ <!-- Per notification listener, a summary of how many apps this listener cannot see
+ notifications from -->
+ <plurals name="notif_listener_excluded_summary_nonzero">
+ <item quantity="one">%d app is not bridged</item>
+ <item quantity="other">%d apps are not bridged</item>
+ </plurals>
+
+ <!-- Per notification listener, a list of apps whose notifications this listener cannot see -->
+ <string name="notif_listener_excluded_app_title">Bridged apps</string>
+
<!-- Title for managing VR (virtual reality) helper services. [CHAR LIMIT=50] -->
<string name="vr_listeners_title">VR helper services</string>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 398fa4d..67d857f 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -592,11 +592,6 @@
android:title="@string/show_notification_channel_warnings"
android:summary="@string/show_notification_channel_warnings_summary" />
- <SwitchPreference
- android:key="asst_feedback_indicator"
- android:title="@string/asst_feedback_indicator_title"
- settings:controller="com.android.settings.notification.AssistantFeedbackPreferenceController" />
-
<com.android.settingslib.widget.LayoutPreference
android:key="asst_importance_reset"
android:title="@string/asst_importance_reset_title"
diff --git a/res/xml/notification_access_bridged_apps_settings.xml b/res/xml/notification_access_bridged_apps_settings.xml
new file mode 100644
index 0000000..590a468
--- /dev/null
+++ b/res/xml/notification_access_bridged_apps_settings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="nonbridged_apps"
+ android:title="@string/notif_listener_excluded_app_title"
+ settings:controller="com.android.settings.applications.specialaccess.notificationaccess.BridgedAppsPreferenceController"
+ settings:searchable="false">
+</PreferenceScreen>
diff --git a/res/xml/notification_access_permission_details.xml b/res/xml/notification_access_permission_details.xml
index f7d928d..edac955 100644
--- a/res/xml/notification_access_permission_details.xml
+++ b/res/xml/notification_access_permission_details.xml
@@ -41,11 +41,11 @@
style="@style/SettingsMultiSelectListPreference"
settings:controller="com.android.settings.applications.specialaccess.notificationaccess.TypeFilterPreferenceController"/>/>
- <PreferenceCategory
- android:key="advanced"
- android:order="50"
- settings:initialExpandedChildrenCount="0">
+ <Preference
+ android:key="bridged_apps"
+ android:title="@string/notif_listener_excluded_app_title"
+ android:fragment="com.android.settings.applications.specialaccess.notificationaccess.BridgedAppsSettings"
+ settings:searchable="false"
+ settings:controller="com.android.settings.applications.specialaccess.notificationaccess.BridgedAppsPreferenceController" />
-
- </PreferenceCategory>
</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java
new file mode 100644
index 0000000..9186bdb1
--- /dev/null
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.settings.applications.specialaccess.notificationaccess;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.VersionedPackage;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerFilter;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.TreeSet;
+
+
+public class BridgedAppsPreferenceController extends BasePreferenceController implements
+ LifecycleObserver, ApplicationsState.Callbacks,
+ AppStateBaseBridge.Callback {
+
+ private ApplicationsState mApplicationsState;
+ private ApplicationsState.Session mSession;
+ private AppFilter mFilter;
+ private PreferenceScreen mScreen;
+
+ private ComponentName mCn;
+ private int mUserId;
+ private NotificationBackend mNm;
+ private NotificationListenerFilter mNlf;
+
+ public BridgedAppsPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ public BridgedAppsPreferenceController setAppState(ApplicationsState appState) {
+ mApplicationsState = appState;
+ return this;
+ }
+
+ public BridgedAppsPreferenceController setCn(ComponentName cn) {
+ mCn = cn;
+ return this;
+ }
+
+ public BridgedAppsPreferenceController setUserId(int userId) {
+ mUserId = userId;
+ return this;
+ }
+
+ public BridgedAppsPreferenceController setNm(NotificationBackend nm) {
+ mNm = nm;
+ return this;
+ }
+
+ public BridgedAppsPreferenceController setFilter(AppFilter filter) {
+ mFilter = filter;
+ return this;
+ }
+
+ public BridgedAppsPreferenceController setSession(Lifecycle lifecycle) {
+ mSession = mApplicationsState.newSession(this, lifecycle);
+ return this;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mScreen = screen;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+
+ @Override
+ public void onExtraInfoUpdated() {
+ rebuild();
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ rebuild();
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {
+ if (apps == null) {
+ return;
+ }
+ mNlf = mNm.getListenerFilter(mCn, mUserId);
+
+ // Create apps key set for removing useless preferences
+ final Set<String> appsKeySet = new TreeSet<>();
+ // Add or update preferences
+ final int N = apps.size();
+ for (int i = 0; i < N; i++) {
+ final AppEntry entry = apps.get(i);
+ if (!shouldAddPreference(entry)) {
+ continue;
+ }
+ final String prefKey = entry.info.packageName + "|" + entry.info.uid;
+ appsKeySet.add(prefKey);
+ SwitchPreference preference = mScreen.findPreference(prefKey);
+ if (preference == null) {
+ preference = new SwitchPreference(mScreen.getContext());
+ preference.setIcon(entry.icon);
+ preference.setTitle(entry.label);
+ preference.setKey(prefKey);
+ mScreen.addPreference(preference);
+ }
+ preference.setOrder(i);
+ preference.setChecked(mNlf.isPackageAllowed(
+ new VersionedPackage(entry.info.packageName, entry.info.uid)));
+ preference.setOnPreferenceChangeListener(this::onPreferenceChange);
+ }
+
+ // Remove preferences that are no longer existing in the updated list of apps
+ removeUselessPrefs(appsKeySet);
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ rebuild();
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ rebuild();
+ }
+
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference instanceof SwitchPreference) {
+ String packageName = preference.getKey().substring(0, preference.getKey().indexOf("|"));
+ int uid = Integer.parseInt(preference.getKey().substring(
+ preference.getKey().indexOf("|") + 1));
+ boolean allowlisted = newValue == Boolean.TRUE;
+ mNlf = mNm.getListenerFilter(mCn, mUserId);
+ if (allowlisted) {
+ mNlf.removePackage(new VersionedPackage(packageName, uid));
+ } else {
+ mNlf.addPackage(new VersionedPackage(packageName, uid));
+ }
+ mNm.setListenerFilter(mCn, mUserId, mNlf);
+ return true;
+ }
+ return false;
+ }
+
+ public void rebuild() {
+ final ArrayList<AppEntry> apps = mSession.rebuild(mFilter,
+ ApplicationsState.ALPHA_COMPARATOR);
+ if (apps != null) {
+ onRebuildComplete(apps);
+ }
+ }
+
+ private void removeUselessPrefs(final Set<String> appsKeySet) {
+ final int prefCount = mScreen.getPreferenceCount();
+ String prefKey;
+ if (prefCount > 0) {
+ for (int i = prefCount - 1; i >= 0; i--) {
+ Preference pref = mScreen.getPreference(i);
+ prefKey = pref.getKey();
+ if (!appsKeySet.contains(prefKey)) {
+ mScreen.removePreference(pref);
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static boolean shouldAddPreference(AppEntry app) {
+ return app != null && UserHandle.isApp(app.info.uid);
+ }
+}
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsSettings.java b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsSettings.java
new file mode 100644
index 0000000..d396a01
--- /dev/null
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsSettings.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.applications.specialaccess.notificationaccess;
+
+import static com.android.settings.applications.AppInfoBase.ARG_PACKAGE_NAME;
+
+import android.app.Application;
+import android.app.settings.SettingsEnums;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+
+public class BridgedAppsSettings extends DashboardFragment {
+
+ private static final String TAG = "BridgedAppsSettings";
+
+ private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 42;
+ private static final String EXTRA_SHOW_SYSTEM = "show_system";
+
+ private boolean mShowSystem;
+ private AppFilter mFilter;
+
+ private int mUserId;
+ private ComponentName mComponentName;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mShowSystem = icicle != null && icicle.getBoolean(EXTRA_SHOW_SYSTEM);
+
+ use(BridgedAppsPreferenceController.class).setNm(new NotificationBackend());
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(Menu.NONE, MENU_SHOW_SYSTEM, Menu.NONE,
+ mShowSystem ? R.string.menu_hide_system : R.string.menu_show_system);
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_SHOW_SYSTEM:
+ mShowSystem = !mShowSystem;
+ item.setTitle(mShowSystem ? R.string.menu_hide_system : R.string.menu_show_system);
+ mFilter = mShowSystem ? ApplicationsState.FILTER_ALL_ENABLED
+ : ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER;
+
+ use(BridgedAppsPreferenceController.class).setFilter(mFilter).rebuild();
+
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mFilter = mShowSystem ? ApplicationsState.FILTER_ALL_ENABLED
+ : ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER;
+
+ final Bundle args = getArguments();
+ Intent intent = (args == null) ?
+ getIntent() : (Intent) args.getParcelable("intent");
+ String cn = args.getString(Settings.EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME);
+ if (cn != null) {
+ mComponentName = ComponentName.unflattenFromString(cn);
+ }
+ if (intent != null && intent.hasExtra(Intent.EXTRA_USER_HANDLE)) {
+ mUserId = ((UserHandle) intent.getParcelableExtra(
+ Intent.EXTRA_USER_HANDLE)).getIdentifier();
+ } else {
+ mUserId = UserHandle.myUserId();
+ }
+
+ use(BridgedAppsPreferenceController.class)
+ .setAppState(ApplicationsState.getInstance(
+ (Application) context.getApplicationContext()))
+ .setCn(mComponentName)
+ .setUserId(mUserId)
+ .setSession(getSettingsLifecycle())
+ .setFilter(mFilter)
+ .rebuild();
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.NOTIFICATION_ACCESS_BRIDGED_APPS;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.notification_access_bridged_apps_settings;
+ }
+}
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
index 9f4b693..41a6efa 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java
@@ -32,15 +32,19 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.util.Log;
import android.util.Slog;
+import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.RestrictedLockUtils;
@@ -52,6 +56,8 @@
public class NotificationAccessDetails extends DashboardFragment {
private static final String TAG = "NotifAccessDetails";
+ private NotificationBackend mNm = new NotificationBackend();
+ private NotificationListenerFilter mNlf;
private ComponentName mComponentName;
private CharSequence mServiceName;
protected PackageInfo mPackageInfo;
@@ -131,6 +137,33 @@
if (!refreshUi()) {
setIntentAndFinish(true /* appChanged */);
}
+ Preference apps = getPreferenceScreen().findPreference(
+ use(BridgedAppsPreferenceController.class).getPreferenceKey());
+ if (apps != null) {
+ mNlf = mNm.getListenerFilter(mComponentName, mUserId);
+ int nonBridgedCount = mNlf.getDisallowedPackages().size();
+ apps.setSummary(nonBridgedCount == 0 ?
+ getString(R.string.notif_listener_excluded_summary_zero)
+ : getResources().getQuantityString(
+ R.plurals.notif_listener_excluded_summary_nonzero,
+ nonBridgedCount, nonBridgedCount));
+
+ apps.setOnPreferenceClickListener(preference -> {
+ final Bundle args = new Bundle();
+ args.putString(AppInfoBase.ARG_PACKAGE_NAME, mPackageName);
+ args.putString(Settings.EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME,
+ mComponentName.flattenToString());
+
+ new SubSettingLauncher(getContext())
+ .setDestination(BridgedAppsSettings.class.getName())
+ .setSourceMetricsCategory(getMetricsCategory())
+ .setTitleRes(R.string.notif_listener_excluded_app_title)
+ .setArguments(args)
+ .setUserHandle(UserHandle.of(mUserId))
+ .launch();
+ return true;
+ });
+ }
}
protected void setIntentAndFinish(boolean appChanged) {
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index ee99e09..a6a211e 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -550,8 +550,11 @@
voiceNetworkTypeName = getNetworkTypeName(actualVoiceNetworkType);
}
- if (overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE
- || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) {
+ final boolean isOverrideNwTypeNrAdvancedOrNsa =
+ overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
+ || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA;
+ if (actualDataNetworkType == TelephonyManager.NETWORK_TYPE_LTE
+ && isOverrideNwTypeNrAdvancedOrNsa) {
dataNetworkTypeName = "NR NSA";
}
diff --git a/src/com/android/settings/fuelgauge/FakeUid.java b/src/com/android/settings/fuelgauge/FakeUid.java
index 309f259..db35e73 100644
--- a/src/com/android/settings/fuelgauge/FakeUid.java
+++ b/src/com/android/settings/fuelgauge/FakeUid.java
@@ -361,6 +361,11 @@
}
@Override
+ public long[] getCustomMeasuredEnergiesMicroJoules() {
+ return null;
+ }
+
+ @Override
public long getMobileRadioApWakeupCount(int which) {
return 0;
}
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index f4377ea..8a7e737 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -49,6 +49,7 @@
import android.text.format.DateUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
+import android.util.Slog;
import androidx.annotation.VisibleForTesting;
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index 13d3912..29330f5 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -312,7 +312,7 @@
switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) {
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
launched = launchConfirmationActivity(request, title, header, description,
- returnCredentials
+ returnCredentials || forceVerifyPath
? ConfirmLockPattern.InternalActivity.class
: ConfirmLockPattern.class, returnCredentials, external,
forceVerifyPath, userId, alternateButton, allowAnyUser,
@@ -325,7 +325,7 @@
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
launched = launchConfirmationActivity(request, title, header, description,
- returnCredentials
+ returnCredentials || forceVerifyPath
? ConfirmLockPassword.InternalActivity.class
: ConfirmLockPassword.class, returnCredentials, external,
forceVerifyPath, userId, alternateButton, allowAnyUser,
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
index 5005399..53d9849 100644
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -243,7 +243,7 @@
mDefaultGuestRestrictions = mUserManager.getDefaultGuestRestrictions();
mPhonePref.setChecked(
!mDefaultGuestRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
- mRemoveUserPref.setTitle(R.string.user_exit_guest_menu);
+ mRemoveUserPref.setTitle(R.string.user_exit_guest_title);
} else {
mPhonePref.setChecked(!mUserManager.hasUserRestriction(
UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId)));
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index fa215e7..8010f41 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -31,7 +31,6 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
@@ -165,7 +164,6 @@
private final Object mUserLock = new Object();
private UserManager mUserManager;
private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<>();
- private static Bitmap sRemoveGuestBitmap = null;
private MultiUserSwitchBarController mSwitchBarController;
private EditUserInfoController mEditUserInfoController =
@@ -179,7 +177,6 @@
// A place to cache the generated default avatar
private Drawable mDefaultIconDrawable;
- private Drawable mRemoveGuestIconDrawable;
// TODO: Replace current Handler solution to something that doesn't leak memory and works
// TODO: during a configuration change
@@ -387,8 +384,8 @@
private void loadProfile() {
if (isCurrentUserGuest()) {
// No need to load profile information
- mMePreference.setIcon(getEncircledRemoveGuestIcon());
- mMePreference.setTitle(R.string.user_clear_guest_menu);
+ mMePreference.setIcon(getEncircledDefaultIcon());
+ mMePreference.setTitle(R.string.user_exit_guest_title);
mMePreference.setSelectable(true);
// removing a guest will result in switching back to the admin user
mMePreference.setEnabled(canSwitchUserNow());
@@ -904,7 +901,7 @@
} else {
setPhotoId(pref, user);
}
- } else if (!user.isGuest()) {
+ } else {
// Icon not available yet, print a placeholder
pref.setIcon(getEncircledDefaultIcon());
}
@@ -1049,14 +1046,6 @@
return mDefaultIconDrawable;
}
- private Drawable getEncircledRemoveGuestIcon() {
- if (mRemoveGuestIconDrawable == null) {
- mRemoveGuestIconDrawable = encircle(
- getRemoveGuestIconAsBitmap(getContext().getResources()));
- }
- return mRemoveGuestIconDrawable;
- }
-
private void setPhotoId(Preference pref, UserInfo user) {
Bitmap bitmap = mUserIcons.get(user.id);
if (bitmap != null) {
@@ -1136,23 +1125,6 @@
}
/**
- * Returns a remove guest icon (as a {@link Bitmap})
- *
- * @param resources resources object to fetch the remove guest icon.
- */
- private static Bitmap getRemoveGuestIconAsBitmap(Resources resources) {
- if (sRemoveGuestBitmap == null) {
- Drawable icon = resources.getDrawable(R.drawable.ic_delete, null).mutate();
- icon.setColorFilter(
- resources.getColor(com.android.internal.R.color.user_icon_default_gray, null),
- PorterDuff.Mode.SRC_IN);
- icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
- sRemoveGuestBitmap = UserIcons.convertToBitmap(icon);
- }
- return sRemoveGuestBitmap;
- }
-
- /**
* Assign the default photo to user with {@paramref userId}
*
* @param context used to get the {@link UserManager}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
index d082bde..053bbe0 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
@@ -120,6 +120,46 @@
.isEqualTo(ThemeHelper.THEME_GLIF_V2);
}
+ @Test
+ public void launchConfirmPattern_ForceVerify_shouldLaunchInternalActivity() {
+ final Activity activity = Robolectric.setupActivity(Activity.class);
+
+ ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(activity);
+ builder.setRequestCode(100)
+ .setForceVerifyPath(true);
+ ChooseLockSettingsHelper helper = getChooseLockSettingsHelper(builder);
+ when(helper.mLockPatternUtils.getKeyguardStoredPasswordQuality(anyInt()))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ helper.launch();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ Intent startedIntent = shadowActivity.getNextStartedActivity();
+
+ assertEquals(new ComponentName("com.android.settings",
+ ConfirmLockPattern.InternalActivity.class.getName()),
+ startedIntent.getComponent());
+ }
+
+ @Test
+ public void launchConfirmPassword_ForceVerify_shouldLaunchInternalActivity() {
+ final Activity activity = Robolectric.setupActivity(Activity.class);
+
+ ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(activity);
+ builder.setRequestCode(100)
+ .setForceVerifyPath(true);
+ ChooseLockSettingsHelper helper = getChooseLockSettingsHelper(builder);
+ when(helper.mLockPatternUtils.getKeyguardStoredPasswordQuality(anyInt()))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
+ helper.launch();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ Intent startedIntent = shadowActivity.getNextStartedActivity();
+
+ assertEquals(new ComponentName("com.android.settings",
+ ConfirmLockPassword.InternalActivity.class.getName()),
+ startedIntent.getComponent());
+ }
+
private ChooseLockSettingsHelper getChooseLockSettingsHelper(
ChooseLockSettingsHelper.Builder builder) {
LockPatternUtils mockLockPatternUtils = mock(LockPatternUtils.class);
diff --git a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
index 50ddd2a..90c9172 100644
--- a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
@@ -363,7 +363,7 @@
mFragment.initialize(mActivity, mArguments);
verify(mRemoveUserPref).setOnPreferenceClickListener(mFragment);
- verify(mRemoveUserPref).setTitle(R.string.user_exit_guest_menu);
+ verify(mRemoveUserPref).setTitle(R.string.user_exit_guest_title);
verify(mFragment, never()).removePreference(KEY_REMOVE_USER);
}
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
index c5f082d..616e6a9 100644
--- a/tests/unit/AndroidManifest.xml
+++ b/tests/unit/AndroidManifest.xml
@@ -28,7 +28,7 @@
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <application>
+ <application android:debuggable="true">
<uses-library android:name="android.test.runner" />
<activity android:name="com.android.settings.tests.BluetoothRequestPermissionTest"
android:exported="true"
diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java
new file mode 100644
index 0000000..3cdbd3a
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.specialaccess.notificationaccess;
+
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.VersionedPackage;
+import android.graphics.drawable.Drawable;
+import android.os.Looper;
+import android.service.notification.NotificationListenerFilter;
+import android.util.ArraySet;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.applications.ApplicationsState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class BridgedAppsPreferenceControllerTest {
+
+ private Context mContext;
+ private BridgedAppsPreferenceController mController;
+ @Mock
+ NotificationBackend mNm;
+ ComponentName mCn = new ComponentName("a", "b");
+ PreferenceScreen mScreen;
+ @Mock
+ ApplicationsState mAppState;
+ private ApplicationsState.AppEntry mAppEntry;
+ private ApplicationsState.AppEntry mAppEntry2;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ApplicationProvider.getApplicationContext();
+
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ mScreen = preferenceManager.createPreferenceScreen(mContext);
+
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = "pkg";
+ ai.uid = 12300;
+ ai.sourceDir = "";
+ ApplicationInfo ai2 = new ApplicationInfo();
+ ai2.packageName = "another";
+ ai2.uid = 18800;
+ ai2.sourceDir = "";
+ mAppEntry = new ApplicationsState.AppEntry(mContext, ai, 0);
+ mAppEntry2 = new ApplicationsState.AppEntry(mContext, ai2, 1);
+
+ mAppEntry.info = ai;
+ mAppEntry.label = "hi";
+ Drawable icon = mock(Drawable.class);
+ mAppEntry.icon = icon;
+
+ mController = new BridgedAppsPreferenceController(mContext, "key");
+ mController.setCn(mCn);
+ mController.setNm(mNm);
+ mController.setUserId(0);
+ mController.setAppState(mAppState);
+ mController.displayPreference(mScreen);
+ }
+
+ @Test
+ public void onRebuildComplete_AddsToScreen() {
+ when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+ when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
+
+ ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
+ entries.add(mAppEntry);
+ entries.add(mAppEntry2);
+
+ mController.onRebuildComplete(entries);
+
+ assertThat(mScreen.getPreferenceCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void onRebuildComplete_doesNotReaddToScreen() {
+ when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+ when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
+
+ SwitchPreference p = mock(SwitchPreference.class);
+ when(p.getKey()).thenReturn("pkg|12300");
+ mScreen.addPreference(p);
+
+ ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
+ entries.add(mAppEntry);
+ entries.add(mAppEntry2);
+
+ mController.onRebuildComplete(entries);
+
+ assertThat(mScreen.getPreferenceCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void onRebuildComplete_removesExtras() {
+ when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+ when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
+
+ Preference p = mock(Preference.class);
+ when(p.getKey()).thenReturn("pkg|123");
+ mScreen.addPreference(p);
+
+ ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
+ entries.add(mAppEntry);
+ entries.add(mAppEntry2);
+
+ mController.onRebuildComplete(entries);
+
+ assertThat((Preference) mScreen.findPreference("pkg|123")).isNull();
+ }
+
+ @Test
+ public void onRebuildComplete_buildsSetting() {
+ when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+ when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
+
+ ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
+ entries.add(mAppEntry);
+
+ mController.onRebuildComplete(entries);
+
+ SwitchPreference actual = mScreen.findPreference("pkg|12300");
+
+ assertThat(actual.isChecked()).isTrue();
+ assertThat(actual.getTitle()).isEqualTo("hi");
+ assertThat(actual.getIcon()).isEqualTo(mAppEntry.icon);
+ }
+
+ @Test
+ public void onPreferenceChange_false() {
+ VersionedPackage vp = new VersionedPackage("pkg", 10567);
+ ArraySet<VersionedPackage> vps = new ArraySet<>();
+ vps.add(vp);
+ NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ONGOING
+ | FLAG_FILTER_TYPE_CONVERSATIONS, vps);
+ when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+ when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
+
+ SwitchPreference pref = new SwitchPreference(mContext);
+ pref.setKey("pkg|567");
+
+ mController.onPreferenceChange(pref, false);
+
+ ArgumentCaptor<NotificationListenerFilter> captor =
+ ArgumentCaptor.forClass(NotificationListenerFilter.class);
+ verify(mNm).setListenerFilter(eq(mCn), eq(0), captor.capture());
+ assertThat(captor.getValue().getDisallowedPackages()).contains(
+ new VersionedPackage("pkg", 567));
+ assertThat(captor.getValue().getDisallowedPackages()).contains(
+ new VersionedPackage("pkg", 10567));
+ }
+
+ @Test
+ public void onPreferenceChange_true() {
+ VersionedPackage vp = new VersionedPackage("pkg", 567);
+ VersionedPackage vp2 = new VersionedPackage("pkg", 10567);
+ ArraySet<VersionedPackage> vps = new ArraySet<>();
+ vps.add(vp);
+ vps.add(vp2);
+ NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ONGOING
+ | FLAG_FILTER_TYPE_CONVERSATIONS, vps);
+ when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
+ when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
+
+ SwitchPreference pref = new SwitchPreference(mContext);
+ pref.setKey("pkg|567");
+
+ mController.onPreferenceChange(pref, true);
+
+ ArgumentCaptor<NotificationListenerFilter> captor =
+ ArgumentCaptor.forClass(NotificationListenerFilter.class);
+ verify(mNm).setListenerFilter(eq(mCn), eq(0), captor.capture());
+ assertThat(captor.getValue().getDisallowedPackages().size()).isEqualTo(1);
+ assertThat(captor.getValue().getDisallowedPackages()).contains(
+ new VersionedPackage("pkg", 10567));
+ }
+}