Snap for 5342135 from fd7e2b43f7 to qt-release
Change-Id: Idff875383b9d5113a33c0931671341dd124dc8ee
This commit is contained in:
@@ -788,7 +788,7 @@
|
||||
|
||||
<activity android:name=".wallpaper.WallpaperSuggestionActivity"
|
||||
android:label="@string/wallpaper_settings_title"
|
||||
android:icon="@drawable/ic_suggestion_wallpaper"
|
||||
android:icon="@drawable/ic_wallpaper"
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<!--
|
||||
Copyright (C) 2019 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,12.71l2.14,2.58l3,-3.87L18,16.57H6L9,12.71zM5,5h6V3H5C3.9,3 3,3.9 3,5v6h2V5zM19,19h-6v2h6c1.1,0 2,-0.9 2,-2v-6h-2V19zM5,19v-6H3v6c0,1.1 0.9,2 2,2h6v-2H5zM19,5v6h2V5c0,-1.1 -0.9,-2 -2,-2h-6v2H19zM16,9c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1c-0.55,0 -1,0.45 -1,1S15.45,9 16,9z"/>
|
||||
</vector>
|
||||
56
res/layout/manage_applications_apps_unsupported.xml
Normal file
56
res/layout/manage_applications_apps_unsupported.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/disabled_feature"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/disabled_feature_reason_slow_down_phone"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<FrameLayout
|
||||
android:id="@+id/pinned_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
settings:layout_scrollFlags="scroll|enterAlways"/>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -10183,6 +10183,10 @@
|
||||
|
||||
<!-- Note displayed when certain features are not available on low ram devices. [CHAR LIMIT=NONE] -->
|
||||
<string name="disabled_low_ram_device">This feature is not available on this device</string>
|
||||
<!-- Note displayed when certain features are not available. [CHAR LIMIT=NONE] -->
|
||||
<string name="disabled_feature">This feature is not available</string>
|
||||
<!-- Note displayed to explain that a feature is not available because it will slow down the phone. [CHAR LIMIT=NONE] -->
|
||||
<string name="disabled_feature_reason_slow_down_phone">It will slow down this phone</string>
|
||||
|
||||
<!-- UI debug setting: preference title - enforce full raw GNSS satellite measurements [CHAR LIMIT=60] -->
|
||||
<string name="enable_gnss_raw_meas_full_tracking">Force full GNSS measurements</string>
|
||||
|
||||
@@ -58,6 +58,14 @@
|
||||
android:title="@string/screen_zoom_title"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<ListPreference
|
||||
android:key="dark_ui_mode_accessibility"
|
||||
android:title="@string/dark_ui_mode"
|
||||
android:dialogTitle="@string/dark_ui_mode_title"
|
||||
android:entries="@array/dark_ui_mode_entries"
|
||||
android:entryValues="@array/dark_ui_mode_values"
|
||||
settings:searchable="false" />
|
||||
|
||||
<Preference
|
||||
android:fragment="com.android.settings.accessibility.MagnificationPreferenceFragment"
|
||||
android:key="magnification_preference_screen"
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
android:key="all_app_info"
|
||||
android:title="@string/applications_settings"
|
||||
android:order="-999"
|
||||
android:fragment="com.android.settings.applications.manageapplications.ManageApplications"/>
|
||||
android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
|
||||
settings:controller="com.android.settings.applications.AllAppsInfoPreferenceController"/>
|
||||
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="recent_open_apps"
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
android:key="system_alert_window"
|
||||
android:title="@string/system_alert_window_settings"
|
||||
android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
|
||||
settings:keywords="@string/keywords_system_alert_window">
|
||||
settings:keywords="@string/keywords_system_alert_window"
|
||||
settings:controller="com.android.settings.applications.specialaccess.SystemAlertWindowPreferenceController">
|
||||
<extra
|
||||
android:name="classname"
|
||||
android:value="com.android.settings.Settings$OverlaySettingsActivity" />
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.widget.Button;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.core.InstrumentedFragment;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public class CryptKeeperConfirm extends InstrumentedFragment {
|
||||
@@ -87,7 +88,12 @@ public class CryptKeeperConfirm extends InstrumentedFragment {
|
||||
IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
|
||||
try {
|
||||
Bundle args = getIntent().getExtras();
|
||||
storageManager.encryptStorage(args.getInt("type", -1), args.getString("password"));
|
||||
// TODO(b/120484642): Update vold to accept a password as a byte array
|
||||
byte[] passwordBytes = args.getByteArray("password");
|
||||
String password = passwordBytes != null ? new String(passwordBytes) : null;
|
||||
Arrays.fill(passwordBytes, (byte) 0);
|
||||
storageManager.encryptStorage(args.getInt("type", -1),
|
||||
password);
|
||||
} catch (Exception e) {
|
||||
Log.e("CryptKeeper", "Error while encrypting...", e);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.INetworkManagementService;
|
||||
@@ -1007,4 +1008,14 @@ public final class Utils extends com.android.settingslib.Utils {
|
||||
return context.getResources();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if SYSTEM_ALERT_WINDOW permission is available.
|
||||
* Starting from Q, SYSTEM_ALERT_WINDOW is disabled on low ram phones.
|
||||
*/
|
||||
public static boolean isSystemAlertWindowEnabled(Context context) {
|
||||
// SYSTEM_ALERT_WINDOW is disabled on on low ram devices starting from Q
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
return !(am.isLowRamDevice() && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ import com.android.internal.view.RotationPolicy.RotationPolicyListener;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.display.DarkUIPreferenceController;
|
||||
import com.android.settings.display.ToggleFontSizePreferenceFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
@@ -133,6 +134,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
"accessibility_content_timeout_preference_fragment";
|
||||
private static final String ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE =
|
||||
"accessibility_control_timeout_preference_fragment";
|
||||
private static final String DARK_UI_MODE_PREFERENCE =
|
||||
"dark_ui_mode_accessibility";
|
||||
|
||||
|
||||
// Extras passed to sub-fragments.
|
||||
@@ -236,6 +239,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
private SwitchPreference mToggleInversionPreference;
|
||||
private ColorInversionPreferenceController mInversionPreferenceController;
|
||||
private AccessibilityHearingAidPreferenceController mHearingAidPreferenceController;
|
||||
private ListPreference mDarkUIModePreference;
|
||||
private DarkUIPreferenceController mDarkUIPreferenceController;
|
||||
|
||||
private int mLongPressTimeoutDefault;
|
||||
|
||||
@@ -501,6 +506,13 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
|
||||
// Vibrations.
|
||||
mVibrationPreferenceScreen = findPreference(VIBRATION_PREFERENCE_SCREEN);
|
||||
|
||||
// Dark Mode.
|
||||
mDarkUIModePreference = findPreference(DARK_UI_MODE_PREFERENCE);
|
||||
mDarkUIPreferenceController = new DarkUIPreferenceController(getContext(),
|
||||
DARK_UI_MODE_PREFERENCE);
|
||||
mDarkUIPreferenceController.displayPreference(getPreferenceScreen());
|
||||
mDarkUIModePreference.setSummary(mDarkUIPreferenceController.getSummary());
|
||||
}
|
||||
|
||||
private void updateAllPreferences() {
|
||||
@@ -683,6 +695,9 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
// If the quick setting is enabled, the preference MUST be enabled.
|
||||
mInversionPreferenceController.updateState(mToggleInversionPreference);
|
||||
|
||||
// Dark Mode
|
||||
mDarkUIPreferenceController.updateState(mDarkUIModePreference);
|
||||
|
||||
// Power button ends calls.
|
||||
if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
|
||||
&& Utils.isVoiceCapable(getActivity())) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications;
|
||||
|
||||
import android.app.usage.UsageStats;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AllAppsInfoPreferenceController extends BasePreferenceController {
|
||||
|
||||
private List<UsageStats> mRecentApps;
|
||||
|
||||
public AllAppsInfoPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
public void setRecentApps(List<UsageStats> recentApps) {
|
||||
mRecentApps = recentApps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mRecentApps == null || mRecentApps.isEmpty() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
// Show total number of installed apps as See all's summary.
|
||||
new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON,
|
||||
mContext.getPackageManager()) {
|
||||
@Override
|
||||
protected void onCountComplete(int num) {
|
||||
preference.setSummary(mContext.getString(R.string.apps_summary, num));
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,10 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "AppAndNotifDashboard";
|
||||
|
||||
private boolean mIsFirstLaunch;
|
||||
private RecentAppsPreferenceController mRecentAppsPreferenceController;
|
||||
private AllAppsInfoPreferenceController mAllAppsInfoPreferenceController;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.SETTINGS_APP_NOTIF_CATEGORY;
|
||||
@@ -61,7 +65,26 @@ public class AppAndNotificationDashboardFragment extends DashboardFragment {
|
||||
super.onAttach(context);
|
||||
|
||||
use(SpecialAppAccessPreferenceController.class).setSession(getSettingsLifecycle());
|
||||
use(RecentAppsPreferenceController.class).setFragment(this /* fragment */);
|
||||
mRecentAppsPreferenceController = use(RecentAppsPreferenceController.class);
|
||||
mRecentAppsPreferenceController.setFragment(this /* fragment */);
|
||||
|
||||
mAllAppsInfoPreferenceController = use(AllAppsInfoPreferenceController.class);
|
||||
mAllAppsInfoPreferenceController.setRecentApps(
|
||||
mRecentAppsPreferenceController.getRecentApps());
|
||||
|
||||
mIsFirstLaunch = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
if (!mIsFirstLaunch) {
|
||||
mRecentAppsPreferenceController.reloadData();
|
||||
mAllAppsInfoPreferenceController.setRecentApps(
|
||||
mRecentAppsPreferenceController.getRecentApps());
|
||||
}
|
||||
|
||||
super.onResume();
|
||||
mIsFirstLaunch = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -66,8 +66,6 @@ import java.util.Set;
|
||||
public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
implements Comparator<UsageStats> {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String KEY_ALL_APP_INFO = "all_app_info";
|
||||
@VisibleForTesting
|
||||
static final String KEY_DIVIDER = "recent_apps_divider";
|
||||
|
||||
@@ -79,11 +77,7 @@ public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
@VisibleForTesting
|
||||
LayoutPreference mRecentAppsPreference;
|
||||
@VisibleForTesting
|
||||
Preference mAllAppPref;
|
||||
@VisibleForTesting
|
||||
Preference mDivider;
|
||||
@VisibleForTesting
|
||||
boolean mIsFirstLaunch;
|
||||
|
||||
private final PackageManager mPm;
|
||||
private final UsageStatsManager mUsageStatsManager;
|
||||
@@ -119,7 +113,6 @@ public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
mPowerManager = mContext.getSystemService(PowerManager.class);
|
||||
mUsageStatsManager = mContext.getSystemService(UsageStatsManager.class);
|
||||
mRecentApps = new ArrayList<>();
|
||||
mIsFirstLaunch = true;
|
||||
reloadData();
|
||||
}
|
||||
|
||||
@@ -129,14 +122,13 @@ public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mRecentApps.isEmpty() ? AVAILABLE_UNSEARCHABLE : AVAILABLE;
|
||||
return mRecentApps.isEmpty() ? CONDITIONALLY_UNAVAILABLE : AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mAllAppPref = screen.findPreference(KEY_ALL_APP_INFO);
|
||||
mDivider = screen.findPreference(KEY_DIVIDER);
|
||||
mRecentAppsPreference = (LayoutPreference) screen.findPreference(getPreferenceKey());
|
||||
final View view = mRecentAppsPreference.findViewById(R.id.app_entities_header);
|
||||
@@ -157,26 +149,18 @@ public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
// In order to improve launch time, we don't load data again at first launch.
|
||||
if (!mIsFirstLaunch) {
|
||||
reloadData();
|
||||
refreshUi();
|
||||
}
|
||||
|
||||
refreshUi();
|
||||
// Show total number of installed apps as See all's summary.
|
||||
new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON,
|
||||
mContext.getPackageManager()) {
|
||||
@Override
|
||||
protected void onCountComplete(int num) {
|
||||
if (mHasRecentApps) {
|
||||
mAppEntitiesController.setHeaderDetails(
|
||||
mContext.getString(R.string.see_all_apps_title, num));
|
||||
mAppEntitiesController.apply();
|
||||
} else {
|
||||
mAllAppPref.setSummary(mContext.getString(R.string.apps_summary, num));
|
||||
}
|
||||
mAppEntitiesController.setHeaderDetails(
|
||||
mContext.getString(R.string.see_all_apps_title, num));
|
||||
mAppEntitiesController.apply();
|
||||
}
|
||||
}.execute();
|
||||
mIsFirstLaunch = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,14 +169,16 @@ public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
return Long.compare(b.getLastTimeUsed(), a.getLastTimeUsed());
|
||||
}
|
||||
|
||||
List<UsageStats> getRecentApps() {
|
||||
return mRecentApps;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void refreshUi() {
|
||||
if (mRecentApps != null && !mRecentApps.isEmpty()) {
|
||||
mHasRecentApps = true;
|
||||
displayRecentApps();
|
||||
} else {
|
||||
mHasRecentApps = false;
|
||||
displayOnlyAppInfo();
|
||||
mDivider.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,13 +195,6 @@ public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
updateDisplayableRecentAppList();
|
||||
}
|
||||
|
||||
private void displayOnlyAppInfo() {
|
||||
mDivider.setVisible(false);
|
||||
mAllAppPref.setTitle(R.string.applications_settings);
|
||||
mAllAppPref.setVisible(true);
|
||||
mRecentAppsPreference.setVisible(false);
|
||||
}
|
||||
|
||||
private void displayRecentApps() {
|
||||
int showAppsCount = 0;
|
||||
|
||||
@@ -230,8 +209,6 @@ public class RecentAppsPreferenceController extends BasePreferenceController
|
||||
}
|
||||
}
|
||||
mAppEntitiesController.apply();
|
||||
mRecentAppsPreference.setVisible(true);
|
||||
mAllAppPref.setVisible(false);
|
||||
mDivider.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.android.settings.applications.appinfo;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
@@ -25,6 +26,9 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
@@ -36,6 +40,7 @@ import androidx.preference.Preference.OnPreferenceClickListener;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.applications.AppInfoWithHeader;
|
||||
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
|
||||
import com.android.settings.applications.AppStateOverlayBridge;
|
||||
@@ -70,6 +75,11 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc
|
||||
mOverlayBridge = new AppStateOverlayBridge(context, mState, null);
|
||||
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
|
||||
|
||||
if (!Utils.isSystemAlertWindowEnabled(context)) {
|
||||
mPackageInfo = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// find preferences
|
||||
addPreferencesFromResource(R.xml.draw_overlay_permissions_details);
|
||||
mSwitchPref = (SwitchPreference) findPreference(KEY_APP_OPS_SETTINGS_SWITCH);
|
||||
@@ -81,6 +91,18 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc
|
||||
.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
|
||||
}
|
||||
|
||||
// Override here so we don't have an empty screen
|
||||
@Override
|
||||
public View onCreateView (LayoutInflater inflater,
|
||||
ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// if we don't have a package info, show a page saying this is unsupported
|
||||
if (mPackageInfo == null) {
|
||||
return inflater.inflate(R.layout.manage_applications_apps_unsupported, null);
|
||||
}
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -142,6 +164,8 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc
|
||||
|
||||
@Override
|
||||
protected boolean refreshUi() {
|
||||
if (mPackageInfo == null) return true;
|
||||
|
||||
mOverlayState = mOverlayBridge.getOverlayInfo(mPackageName,
|
||||
mPackageInfo.applicationInfo.uid);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import static com.android.settings.applications.manageapplications.AppFilterRegi
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.StringRes;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.app.usage.IUsageStatsManager;
|
||||
import android.content.Context;
|
||||
@@ -49,18 +50,22 @@ import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.Filter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.SearchView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -79,6 +84,7 @@ import com.android.settings.Settings.StorageUseActivity;
|
||||
import com.android.settings.Settings.UsageAccessSettingsActivity;
|
||||
import com.android.settings.Settings.WriteSettingsActivity;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.applications.AppInfoBase;
|
||||
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
|
||||
import com.android.settings.applications.AppStateBaseBridge;
|
||||
@@ -327,12 +333,19 @@ public class ManageApplications extends InstrumentedFragment
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
if (mListType == LIST_TYPE_OVERLAY && !Utils.isSystemAlertWindowEnabled(getContext())) {
|
||||
mRootView = inflater.inflate(R.layout.manage_applications_apps_unsupported, null);
|
||||
setHasOptionsMenu(false);
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
mRootView = inflater.inflate(R.layout.manage_applications_apps, null);
|
||||
mLoadingContainer = mRootView.findViewById(R.id.loading_container);
|
||||
mListContainer = mRootView.findViewById(R.id.list_container);
|
||||
if (mListContainer != null) {
|
||||
// Create adapter and list view here
|
||||
mEmptyView = mListContainer.findViewById(android.R.id.empty);
|
||||
|
||||
mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter,
|
||||
savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.applications.specialaccess;
|
||||
|
||||
import static com.android.settings.Utils.isSystemAlertWindowEnabled;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
public class SystemAlertWindowPreferenceController extends BasePreferenceController {
|
||||
public SystemAlertWindowPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return isSystemAlertWindowEnabled(mContext)
|
||||
? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE ;
|
||||
}
|
||||
}
|
||||
@@ -164,8 +164,7 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
||||
new BatteryMeterView.BatteryMeterDrawable(context,
|
||||
context.getColor(R.color.meter_background_color));
|
||||
drawable.setBatteryLevel(level);
|
||||
drawable.setShowPercent(false);
|
||||
drawable.setBatteryColorFilter(new PorterDuffColorFilter(
|
||||
drawable.setColorFilter(new PorterDuffColorFilter(
|
||||
com.android.settings.Utils.getColorAttrDefaultColor(context,
|
||||
android.R.attr.colorControlNormal),
|
||||
PorterDuff.Mode.SRC_IN));
|
||||
|
||||
@@ -27,9 +27,19 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class FilteredCountryTimeZones {
|
||||
|
||||
// New timezone list and the meta data of time zone, notUsedAfter, is introduced in Android P
|
||||
// in 2018. Only show time zone used in or after 2018.
|
||||
private static final long MIN_USE_DATE_OF_TIMEZONE = 1514764800000L; // 1/1/2018 00:00 UTC
|
||||
/**
|
||||
* The timestamp used to determine which time zones to show to users by using the notUsedAfter
|
||||
* metadata Android holds for each time zone.
|
||||
*
|
||||
* notUsedAfter exists because some time zones effectively "merge" with other time zones after
|
||||
* a given point in time (i.e. they have identical transitions, offsets, etc.). After that
|
||||
* point we only need to show one of the functionally identical ones.
|
||||
*
|
||||
* Rather than using System.currentTimeMillis(), UX folks asked for consistent behavior and so
|
||||
* a timestamp known to be in the recent past is used. This should be updated occasionally but
|
||||
* it doesn't have to be very often.
|
||||
*/
|
||||
private static final long MIN_USE_DATE_OF_TIMEZONE = 1546300800000L; // 1/1/2019 00:00 UTC
|
||||
|
||||
private final CountryTimeZones mCountryTimeZones;
|
||||
private final List<String> mTimeZoneIds;
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
package com.android.settings.display;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class AmbientDisplayAlwaysOnPreferenceController extends TogglePreferenceController {
|
||||
|
||||
@@ -17,6 +17,7 @@ import static android.provider.Settings.Secure.DOZE_ENABLED;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
@@ -24,7 +25,6 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
|
||||
@@ -29,7 +29,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settingslib.graph.BatteryMeterDrawableBase;
|
||||
import com.android.settingslib.graph.ThemedBatteryDrawable;
|
||||
|
||||
public class BatteryMeterView extends ImageView {
|
||||
@VisibleForTesting
|
||||
@@ -54,29 +54,27 @@ public class BatteryMeterView extends ImageView {
|
||||
final int frameColor = context.getColor(R.color.meter_background_color);
|
||||
mAccentColorFilter = new PorterDuffColorFilter(
|
||||
Utils.getColorAttrDefaultColor(context, android.R.attr.colorAccent),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
PorterDuff.Mode.SRC);
|
||||
mErrorColorFilter = new PorterDuffColorFilter(
|
||||
context.getColor(R.color.battery_icon_color_error), PorterDuff.Mode.SRC_IN);
|
||||
|
||||
mDrawable = new BatteryMeterDrawable(context, frameColor);
|
||||
mDrawable.setShowPercent(false);
|
||||
mDrawable.setBatteryColorFilter(mAccentColorFilter);
|
||||
mDrawable.setWarningColorFilter(
|
||||
new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN));
|
||||
mDrawable.setColorFilter(mAccentColorFilter);
|
||||
setImageDrawable(mDrawable);
|
||||
setLayerType(LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
|
||||
public void setBatteryLevel(int level) {
|
||||
mDrawable.setBatteryLevel(level);
|
||||
if (level < mDrawable.getCriticalLevel()) {
|
||||
mDrawable.setBatteryColorFilter(mErrorColorFilter);
|
||||
mDrawable.setColorFilter(mErrorColorFilter);
|
||||
} else {
|
||||
mDrawable.setBatteryColorFilter(mAccentColorFilter);
|
||||
mDrawable.setColorFilter(mAccentColorFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPowerSave(boolean powerSave) {
|
||||
mDrawable.setPowerSave(powerSave);
|
||||
mDrawable.setPowerSaveEnabled(powerSave);
|
||||
mPowerSaveEnabled = powerSave;
|
||||
}
|
||||
|
||||
@@ -85,7 +83,7 @@ public class BatteryMeterView extends ImageView {
|
||||
}
|
||||
|
||||
public int getBatteryLevel() {
|
||||
return mDrawable.getBatteryLevel();
|
||||
return mDrawable.getLevel();
|
||||
}
|
||||
|
||||
public void setCharging(boolean charging) {
|
||||
@@ -97,7 +95,7 @@ public class BatteryMeterView extends ImageView {
|
||||
return mDrawable.getCharging();
|
||||
}
|
||||
|
||||
public static class BatteryMeterDrawable extends BatteryMeterDrawableBase {
|
||||
public static class BatteryMeterDrawable extends ThemedBatteryDrawable {
|
||||
private final int mIntrinsicWidth;
|
||||
private final int mIntrinsicHeight;
|
||||
|
||||
@@ -119,16 +117,5 @@ public class BatteryMeterView extends ImageView {
|
||||
public int getIntrinsicHeight() {
|
||||
return mIntrinsicHeight;
|
||||
}
|
||||
|
||||
public void setWarningColorFilter(@Nullable ColorFilter colorFilter) {
|
||||
mWarningTextPaint.setColorFilter(colorFilter);
|
||||
}
|
||||
|
||||
public void setBatteryColorFilter(@Nullable ColorFilter colorFilter) {
|
||||
mFramePaint.setColorFilter(colorFilter);
|
||||
mBatteryPaint.setColorFilter(colorFilter);
|
||||
mBoltPaint.setColorFilter(colorFilter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,14 +21,13 @@ import static android.provider.Settings.Secure.DOZE_DOUBLE_TAP_GESTURE;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
|
||||
public class DoubleTapScreenPreferenceController extends GesturePreferenceController {
|
||||
|
||||
private final int ON = 1;
|
||||
|
||||
@@ -19,9 +19,9 @@ package com.android.settings.gestures;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
||||
|
||||
@@ -18,9 +18,9 @@ package com.android.settings.gestures;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
|
||||
@@ -18,11 +18,11 @@ package com.android.settings.gestures;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
@@ -21,12 +21,11 @@ import static android.provider.Settings.Secure.DOZE_PICK_UP_GESTURE;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
|
||||
public class PickupGesturePreferenceController extends GesturePreferenceController {
|
||||
|
||||
private static final int ON = 1;
|
||||
|
||||
@@ -19,9 +19,9 @@ package com.android.settings.gestures;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
||||
|
||||
@@ -20,12 +20,11 @@ import static android.provider.Settings.Secure.DOZE_TAP_SCREEN_GESTURE;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
|
||||
public class TapScreenGesturePreferenceController extends GesturePreferenceController {
|
||||
|
||||
private static final String PREF_KEY_VIDEO = "gesture_tap_screen_video";
|
||||
|
||||
@@ -18,9 +18,9 @@ package com.android.settings.gestures;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
|
||||
@@ -20,12 +20,12 @@ import static android.provider.Settings.Secure.DOZE_WAKE_SCREEN_GESTURE;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
|
||||
@@ -39,12 +39,18 @@ public class CardContentProvider extends ContentProvider {
|
||||
|
||||
public static final String CARD_AUTHORITY = "com.android.settings.homepage.CardContentProvider";
|
||||
|
||||
public static final Uri URI = new Uri.Builder()
|
||||
public static final Uri REFRESH_CARD_URI = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(CardContentProvider.CARD_AUTHORITY)
|
||||
.appendPath(CardDatabaseHelper.CARD_TABLE)
|
||||
.build();
|
||||
|
||||
public static final Uri DELETE_CARD_URI = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(CardContentProvider.CARD_AUTHORITY)
|
||||
.appendPath(CardDatabaseHelper.CardColumns.CARD_DISMISSED)
|
||||
.build();
|
||||
|
||||
private static final String TAG = "CardContentProvider";
|
||||
/** URI matcher for ContentProvider queries. */
|
||||
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
@@ -208,7 +208,7 @@ public class CardDatabaseHelper extends SQLiteOpenHelper {
|
||||
* Mark a specific ContextualCard with dismissal flag in the database to indicate that the
|
||||
* card has been dismissed.
|
||||
*
|
||||
* @param context Context
|
||||
* @param context Context
|
||||
* @param cardName The card name of the ContextualCard which is dismissed by user.
|
||||
* @return The number of rows updated
|
||||
*/
|
||||
@@ -220,7 +220,7 @@ public class CardDatabaseHelper extends SQLiteOpenHelper {
|
||||
final String[] selectionArgs = {cardName};
|
||||
final int rowsUpdated = database.update(CARD_TABLE, values, selection, selectionArgs);
|
||||
database.close();
|
||||
context.getContentResolver().notifyChange(CardContentProvider.URI, null);
|
||||
context.getContentResolver().notifyChange(CardContentProvider.DELETE_CARD_URI, null);
|
||||
return rowsUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,13 +59,16 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
private final ContentObserver mObserver = new ContentObserver(
|
||||
new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
if (isStarted()) {
|
||||
mNotifyUri = uri;
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@VisibleForTesting
|
||||
Uri mNotifyUri;
|
||||
private Context mContext;
|
||||
|
||||
ContextualCardLoader(Context context) {
|
||||
@@ -77,7 +80,10 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
super.onStartLoading();
|
||||
mContext.getContentResolver().registerContentObserver(CardContentProvider.URI,
|
||||
mNotifyUri = null;
|
||||
mContext.getContentResolver().registerContentObserver(CardContentProvider.REFRESH_CARD_URI,
|
||||
false /*notifyForDescendants*/, mObserver);
|
||||
mContext.getContentResolver().registerContentObserver(CardContentProvider.DELETE_CARD_URI,
|
||||
false /*notifyForDescendants*/, mObserver);
|
||||
}
|
||||
|
||||
@@ -156,10 +162,12 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
// Two large cards
|
||||
return visibleCards;
|
||||
} finally {
|
||||
//TODO(b/121196921): Should not call this if user click dismiss
|
||||
final ContextualCardFeatureProvider contextualCardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
|
||||
contextualCardFeatureProvider.logContextualCardDisplay(visibleCards, hiddenCards);
|
||||
if (!CardContentProvider.DELETE_CARD_URI.equals(mNotifyUri)) {
|
||||
final ContextualCardFeatureProvider contextualCardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext)
|
||||
.getContextualCardFeatureProvider(mContext);
|
||||
contextualCardFeatureProvider.logContextualCardDisplay(visibleCards, hiddenCards);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,8 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
||||
sliceLiveData.observe(mLifecycleOwner, slice -> {
|
||||
if (slice == null) {
|
||||
Log.w(TAG, "Slice is null");
|
||||
mContext.getContentResolver().notifyChange(CardContentProvider.URI, null);
|
||||
mContext.getContentResolver().notifyChange(CardContentProvider.REFRESH_CARD_URI,
|
||||
null);
|
||||
return;
|
||||
} else {
|
||||
//TODO(b/120629936): Take this out once blank card issue is fixed.
|
||||
|
||||
@@ -76,6 +76,7 @@ import com.android.settingslib.RestrictedPreference;
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
import com.android.settingslib.widget.FooterPreferenceMixinCompat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ChooseLockGeneric extends SettingsActivity {
|
||||
@@ -151,7 +152,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
private boolean mPasswordConfirmed = false;
|
||||
private boolean mWaitingForConfirmation = false;
|
||||
private boolean mForChangeCredRequiredForBoot = false;
|
||||
private String mUserPassword;
|
||||
private byte[] mUserPassword;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private FingerprintManager mFingerprintManager;
|
||||
private FaceManager mFaceManager;
|
||||
@@ -200,7 +201,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
.getBooleanExtra(CONFIRM_CREDENTIALS, true);
|
||||
if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
|
||||
mPasswordConfirmed = !confirmCredentials;
|
||||
mUserPassword = getActivity().getIntent().getStringExtra(
|
||||
mUserPassword = getActivity().getIntent().getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
@@ -224,7 +225,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
|
||||
mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
|
||||
if (mUserPassword == null) {
|
||||
mUserPassword = savedInstanceState.getString(
|
||||
mUserPassword = savedInstanceState.getByteArray(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
}
|
||||
}
|
||||
@@ -383,11 +384,11 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
|
||||
mPasswordConfirmed = true;
|
||||
mUserPassword = data != null
|
||||
? data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
|
||||
? data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
|
||||
: null;
|
||||
updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||
if (mForChangeCredRequiredForBoot) {
|
||||
if (!TextUtils.isEmpty(mUserPassword)) {
|
||||
if (!(mUserPassword == null || mUserPassword.length == 0)) {
|
||||
maybeEnableEncryption(
|
||||
mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
|
||||
} else {
|
||||
@@ -447,7 +448,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
|
||||
outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
|
||||
if (mUserPassword != null) {
|
||||
outState.putString(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
|
||||
outState.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +670,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
setPreferenceSummary(ScreenLockType.MANAGED, R.string.secure_lock_encryption_warning);
|
||||
}
|
||||
|
||||
protected Intent getLockManagedPasswordIntent(String password) {
|
||||
protected Intent getLockManagedPasswordIntent(byte[] password) {
|
||||
return mManagedPasswordProvider.createIntent(false, password);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ChooseLockPassword extends SettingsActivity {
|
||||
@@ -123,7 +124,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
return this;
|
||||
}
|
||||
|
||||
public IntentBuilder setPassword(String password) {
|
||||
public IntentBuilder setPassword(byte[] password) {
|
||||
mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, password);
|
||||
return this;
|
||||
}
|
||||
@@ -185,8 +186,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
private static final String KEY_CURRENT_PASSWORD = "current_password";
|
||||
private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
|
||||
|
||||
private String mCurrentPassword;
|
||||
private String mChosenPassword;
|
||||
private byte[] mCurrentPassword;
|
||||
private byte[] mChosenPassword;
|
||||
private boolean mHasChallenge;
|
||||
private long mChallenge;
|
||||
private ImeAwareEditText mPasswordEntry;
|
||||
@@ -215,7 +216,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
protected boolean mForFingerprint;
|
||||
protected boolean mForFace;
|
||||
|
||||
private String mFirstPin;
|
||||
private byte[] mFirstPin;
|
||||
private RecyclerView mPasswordRestrictionView;
|
||||
protected boolean mIsAlphaMode;
|
||||
protected FooterButton mSkipOrClearButton;
|
||||
@@ -234,7 +235,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
private static final int MIN_NUMBER_IN_PASSWORD = 4;
|
||||
private static final int MIN_NON_LETTER_IN_PASSWORD = 5;
|
||||
|
||||
// Error code returned from {@link #validatePassword(String)}.
|
||||
// Error code returned from {@link #validatePassword(byte[])}.
|
||||
static final int NO_ERROR = 0;
|
||||
static final int CONTAIN_INVALID_CHARACTERS = 1 << 0;
|
||||
static final int TOO_SHORT = 1 << 1;
|
||||
@@ -394,12 +395,13 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
SaveAndFinishWorker w = new SaveAndFinishWorker();
|
||||
final boolean required = getActivity().getIntent().getBooleanExtra(
|
||||
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
|
||||
String current = intent.getStringExtra(
|
||||
byte[] currentBytes = intent.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
|
||||
w.setBlocking(true);
|
||||
w.setListener(this);
|
||||
w.start(mChooseLockSettingsHelper.utils(), required,
|
||||
false, 0, current, current, mRequestedQuality, mUserId);
|
||||
w.start(mChooseLockSettingsHelper.utils(), required, false, 0,
|
||||
currentBytes, currentBytes, mRequestedQuality, mUserId);
|
||||
}
|
||||
mTextChangedHandler = new TextChangedHandler();
|
||||
}
|
||||
@@ -474,7 +476,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
Intent intent = getActivity().getIntent();
|
||||
final boolean confirmCredentials = intent.getBooleanExtra(
|
||||
ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
|
||||
mCurrentPassword = intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
mCurrentPassword = intent.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
mHasChallenge = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
|
||||
mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
|
||||
@@ -486,8 +489,9 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mUserId);
|
||||
}
|
||||
} else {
|
||||
|
||||
// restore from previous state
|
||||
mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
|
||||
mFirstPin = savedInstanceState.getByteArray(KEY_FIRST_PIN);
|
||||
final String state = savedInstanceState.getString(KEY_UI_STAGE);
|
||||
if (state != null) {
|
||||
mUiStage = Stage.valueOf(state);
|
||||
@@ -495,7 +499,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
}
|
||||
|
||||
if (mCurrentPassword == null) {
|
||||
mCurrentPassword = savedInstanceState.getString(KEY_CURRENT_PASSWORD);
|
||||
mCurrentPassword = savedInstanceState.getByteArray(KEY_CURRENT_PASSWORD);
|
||||
}
|
||||
|
||||
// Re-attach to the exiting worker if there is one.
|
||||
@@ -553,8 +557,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(KEY_UI_STAGE, mUiStage.name());
|
||||
outState.putString(KEY_FIRST_PIN, mFirstPin);
|
||||
outState.putString(KEY_CURRENT_PASSWORD, mCurrentPassword);
|
||||
outState.putByteArray(KEY_FIRST_PIN, mFirstPin);
|
||||
outState.putByteArray(KEY_CURRENT_PASSWORD, mCurrentPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -567,7 +571,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
getActivity().setResult(RESULT_FINISHED);
|
||||
getActivity().finish();
|
||||
} else {
|
||||
mCurrentPassword = data.getStringExtra(
|
||||
mCurrentPassword = data.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
}
|
||||
break;
|
||||
@@ -712,22 +716,22 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
* @return the validation result.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
int validatePassword(String password) {
|
||||
int validatePassword(byte[] password) {
|
||||
int errorCode = NO_ERROR;
|
||||
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
|
||||
mergeMinComplexityAndDpmRequirements(metrics.quality);
|
||||
|
||||
if (password.length() < mPasswordMinLength) {
|
||||
if (password == null || password.length < mPasswordMinLength) {
|
||||
if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
|
||||
errorCode |= TOO_SHORT;
|
||||
}
|
||||
} else if (password.length() > mPasswordMaxLength) {
|
||||
} else if (password.length > mPasswordMaxLength) {
|
||||
errorCode |= TOO_LONG;
|
||||
} else {
|
||||
// The length requirements are fulfilled.
|
||||
if (!mPasswordNumSequenceAllowed
|
||||
&& !requiresLettersOrSymbols()
|
||||
&& metrics.numeric == password.length()) {
|
||||
&& metrics.numeric == password.length) {
|
||||
// Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
|
||||
// if DevicePolicyManager or min password complexity requires a complex numeric
|
||||
// password. There can be two cases in the UI: 1. User chooses to enroll a
|
||||
@@ -757,8 +761,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
}
|
||||
|
||||
// Allow non-control Latin-1 characters only.
|
||||
for (int i = 0; i < password.length(); i++) {
|
||||
char c = password.charAt(i);
|
||||
for (int i = 0; i < password.length; i++) {
|
||||
char c = (char) password[i];
|
||||
if (c < 32 || c > 127) {
|
||||
errorCode |= CONTAIN_INVALID_CHARACTERS;
|
||||
break;
|
||||
@@ -809,8 +813,9 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
|
||||
public void handleNext() {
|
||||
if (mSaveAndFinishWorker != null) return;
|
||||
mChosenPassword = mPasswordEntry.getText().toString();
|
||||
if (TextUtils.isEmpty(mChosenPassword)) {
|
||||
// TODO(b/120484642): This is a point of entry for passwords from the UI
|
||||
mChosenPassword = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
|
||||
if (mChosenPassword == null || mChosenPassword.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (mUiStage == Stage.Introduction) {
|
||||
@@ -818,9 +823,11 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mFirstPin = mChosenPassword;
|
||||
mPasswordEntry.setText("");
|
||||
updateStage(Stage.NeedToConfirm);
|
||||
} else {
|
||||
Arrays.fill(mChosenPassword, (byte) 0);
|
||||
}
|
||||
} else if (mUiStage == Stage.NeedToConfirm) {
|
||||
if (mFirstPin.equals(mChosenPassword)) {
|
||||
if (Arrays.equals(mFirstPin, mChosenPassword)) {
|
||||
startSaveAndFinish();
|
||||
} else {
|
||||
CharSequence tmp = mPasswordEntry.getText();
|
||||
@@ -828,6 +835,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
Selection.setSelection((Spannable) tmp, 0, tmp.length());
|
||||
}
|
||||
updateStage(Stage.ConfirmWrong);
|
||||
Arrays.fill(mChosenPassword, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -940,8 +948,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
*/
|
||||
protected void updateUi() {
|
||||
final boolean canInput = mSaveAndFinishWorker == null;
|
||||
String password = mPasswordEntry.getText().toString();
|
||||
final int length = password.length();
|
||||
byte[] password = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
|
||||
final int length = password.length;
|
||||
if (mUiStage == Stage.Introduction) {
|
||||
mPasswordRestrictionView.setVisibility(View.VISIBLE);
|
||||
final int errorCode = validatePassword(password);
|
||||
@@ -967,6 +975,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
|
||||
setNextText(mUiStage.buttonText);
|
||||
mPasswordEntryInputDisabler.setInputEnabled(canInput);
|
||||
Arrays.fill(password, (byte) 0);
|
||||
}
|
||||
|
||||
protected int toVisibility(boolean visibleOrGone) {
|
||||
@@ -1025,6 +1034,18 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
|
||||
getActivity().setResult(RESULT_FINISHED, resultData);
|
||||
|
||||
if (mChosenPassword != null) {
|
||||
Arrays.fill(mChosenPassword, (byte) 0);
|
||||
}
|
||||
if (mCurrentPassword != null) {
|
||||
Arrays.fill(mCurrentPassword, (byte) 0);
|
||||
}
|
||||
if (mFirstPin != null) {
|
||||
Arrays.fill(mFirstPin, (byte) 0);
|
||||
}
|
||||
|
||||
mPasswordEntry.setText("");
|
||||
|
||||
if (!wasSecureBefore) {
|
||||
Intent intent = getRedactionInterstitialIntent(getActivity());
|
||||
if (intent != null) {
|
||||
@@ -1061,13 +1082,13 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
|
||||
public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
|
||||
|
||||
private String mChosenPassword;
|
||||
private String mCurrentPassword;
|
||||
private byte[] mChosenPassword;
|
||||
private byte[] mCurrentPassword;
|
||||
private int mRequestedQuality;
|
||||
|
||||
public void start(LockPatternUtils utils, boolean required,
|
||||
boolean hasChallenge, long challenge,
|
||||
String chosenPassword, String currentPassword, int requestedQuality, int userId) {
|
||||
byte[] chosenPassword, byte[] currentPassword, int requestedQuality, int userId) {
|
||||
prepare(utils, required, hasChallenge, challenge, userId);
|
||||
|
||||
mChosenPassword = chosenPassword;
|
||||
|
||||
@@ -55,6 +55,7 @@ import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -114,7 +115,7 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
return this;
|
||||
}
|
||||
|
||||
public IntentBuilder setPattern(String pattern) {
|
||||
public IntentBuilder setPattern(byte[] pattern) {
|
||||
mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pattern);
|
||||
return this;
|
||||
}
|
||||
@@ -187,7 +188,7 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
|
||||
private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
|
||||
|
||||
private String mCurrentPattern;
|
||||
private byte[] mCurrentPattern;
|
||||
private boolean mHasChallenge;
|
||||
private long mChallenge;
|
||||
protected TextView mTitleText;
|
||||
@@ -224,7 +225,7 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
getActivity().setResult(RESULT_FINISHED);
|
||||
getActivity().finish();
|
||||
} else {
|
||||
mCurrentPattern = data.getStringExtra(
|
||||
mCurrentPattern = data.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
@@ -457,12 +458,12 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
SaveAndFinishWorker w = new SaveAndFinishWorker();
|
||||
final boolean required = getActivity().getIntent().getBooleanExtra(
|
||||
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
|
||||
String current = intent.getStringExtra(
|
||||
byte[] current = intent.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
w.setBlocking(true);
|
||||
w.setListener(this);
|
||||
w.start(mChooseLockSettingsHelper.utils(), required,
|
||||
false, 0, LockPatternUtils.stringToPattern(current), current, mUserId);
|
||||
false, 0, LockPatternUtils.byteArrayToPattern(current), current, mUserId);
|
||||
}
|
||||
mForFingerprint = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
@@ -540,7 +541,8 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
final boolean confirmCredentials = getActivity().getIntent()
|
||||
.getBooleanExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
|
||||
Intent intent = getActivity().getIntent();
|
||||
mCurrentPattern = intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
mCurrentPattern =
|
||||
intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
mHasChallenge = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
|
||||
mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
|
||||
@@ -563,13 +565,13 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
}
|
||||
} else {
|
||||
// restore from previous state
|
||||
final String patternString = savedInstanceState.getString(KEY_PATTERN_CHOICE);
|
||||
if (patternString != null) {
|
||||
mChosenPattern = LockPatternUtils.stringToPattern(patternString);
|
||||
final byte[] pattern = savedInstanceState.getByteArray(KEY_PATTERN_CHOICE);
|
||||
if (pattern != null) {
|
||||
mChosenPattern = LockPatternUtils.byteArrayToPattern(pattern);
|
||||
}
|
||||
|
||||
if (mCurrentPattern == null) {
|
||||
mCurrentPattern = savedInstanceState.getString(KEY_CURRENT_PATTERN);
|
||||
mCurrentPattern = savedInstanceState.getByteArray(KEY_CURRENT_PATTERN);
|
||||
}
|
||||
updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
|
||||
|
||||
@@ -665,13 +667,12 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
|
||||
outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
|
||||
if (mChosenPattern != null) {
|
||||
outState.putString(KEY_PATTERN_CHOICE,
|
||||
LockPatternUtils.patternToString(mChosenPattern));
|
||||
outState.putByteArray(KEY_PATTERN_CHOICE,
|
||||
LockPatternUtils.patternToByteArray(mChosenPattern));
|
||||
}
|
||||
|
||||
if (mCurrentPattern != null) {
|
||||
outState.putString(KEY_CURRENT_PATTERN,
|
||||
mCurrentPattern);
|
||||
outState.putByteArray(KEY_CURRENT_PATTERN, mCurrentPattern);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,6 +819,10 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
|
||||
getActivity().setResult(RESULT_FINISHED, resultData);
|
||||
|
||||
if (mCurrentPattern != null) {
|
||||
Arrays.fill(mCurrentPattern, (byte) 0);
|
||||
}
|
||||
|
||||
if (!wasSecureBefore) {
|
||||
Intent intent = getRedactionInterstitialIntent(getActivity());
|
||||
if (intent != null) {
|
||||
@@ -831,12 +836,12 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
|
||||
|
||||
private List<LockPatternView.Cell> mChosenPattern;
|
||||
private String mCurrentPattern;
|
||||
private byte[] mCurrentPattern;
|
||||
private boolean mLockVirgin;
|
||||
|
||||
public void start(LockPatternUtils utils, boolean credentialRequired,
|
||||
boolean hasChallenge, long challenge,
|
||||
List<LockPatternView.Cell> chosenPattern, String currentPattern, int userId) {
|
||||
List<LockPatternView.Cell> chosenPattern, byte[] currentPattern, int userId) {
|
||||
prepare(utils, credentialRequired, hasChallenge, challenge, userId);
|
||||
|
||||
mCurrentPattern = currentPattern;
|
||||
|
||||
@@ -323,8 +323,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
final String pin = mPasswordEntry.getText().toString();
|
||||
if (TextUtils.isEmpty(pin)) {
|
||||
// TODO(b/120484642): This is a point of entry for passwords from the UI
|
||||
final byte[] pin = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
|
||||
if (pin == null || pin.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -350,7 +351,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
return getActivity() instanceof ConfirmLockPassword.InternalActivity;
|
||||
}
|
||||
|
||||
private void startVerifyPassword(final String pin, final Intent intent) {
|
||||
private void startVerifyPassword(final byte[] pin, final Intent intent) {
|
||||
long challenge = getActivity().getIntent().getLongExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
|
||||
final int localEffectiveUserId = mEffectiveUserId;
|
||||
@@ -381,7 +382,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
onVerifyCallback);
|
||||
}
|
||||
|
||||
private void startCheckPassword(final String pin, final Intent intent) {
|
||||
private void startCheckPassword(final byte[] pin, final Intent intent) {
|
||||
final int localEffectiveUserId = mEffectiveUserId;
|
||||
mPendingLockCheck = LockPatternChecker.checkPassword(
|
||||
mLockPatternUtils,
|
||||
|
||||
@@ -448,7 +448,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
mLockPatternUtils, pattern, challenge, localUserId,
|
||||
onVerifyCallback)
|
||||
: LockPatternChecker.verifyTiedProfileChallenge(
|
||||
mLockPatternUtils, LockPatternUtils.patternToString(pattern),
|
||||
mLockPatternUtils, LockPatternUtils.patternToByteArray(pattern),
|
||||
true, challenge, localUserId, onVerifyCallback);
|
||||
}
|
||||
|
||||
@@ -473,7 +473,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
|
||||
StorageManager.CRYPT_TYPE_PATTERN);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
|
||||
LockPatternUtils.patternToString(pattern));
|
||||
LockPatternUtils.patternToByteArray(pattern));
|
||||
}
|
||||
mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
|
||||
localEffectiveUserId);
|
||||
|
||||
@@ -59,7 +59,7 @@ public class ManagedLockPasswordProvider {
|
||||
* @param password Current lock password.
|
||||
* @return Intent that should update lock password to a managed password.
|
||||
*/
|
||||
Intent createIntent(boolean requirePasswordToDecrypt, String password) {
|
||||
Intent createIntent(boolean requirePasswordToDecrypt, byte[] password) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.permission.PermissionControllerManager;
|
||||
import android.permission.RuntimePermissionUsageInfo;
|
||||
import android.provider.DeviceConfig;
|
||||
@@ -31,12 +32,15 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnCreate;
|
||||
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.widget.BarChartInfo;
|
||||
import com.android.settingslib.widget.BarChartPreference;
|
||||
@@ -48,14 +52,17 @@ import java.util.List;
|
||||
|
||||
|
||||
public class PermissionBarChartPreferenceController extends BasePreferenceController implements
|
||||
PermissionControllerManager.OnPermissionUsageResultCallback, LifecycleObserver, OnStart {
|
||||
PermissionControllerManager.OnPermissionUsageResultCallback, LifecycleObserver, OnCreate,
|
||||
OnStart, OnSaveInstanceState {
|
||||
|
||||
private static final String TAG = "BarChartPreferenceCtl";
|
||||
private static final String KEY_PERMISSION_USAGE = "usage_infos";
|
||||
|
||||
@VisibleForTesting
|
||||
List<RuntimePermissionUsageInfo> mOldUsageInfos;
|
||||
private PackageManager mPackageManager;
|
||||
private PrivacyDashboardFragment mParent;
|
||||
private BarChartPreference mBarChartPreference;
|
||||
private List<RuntimePermissionUsageInfo> mOldUsageInfos;
|
||||
|
||||
public PermissionBarChartPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
@@ -67,6 +74,18 @@ public class PermissionBarChartPreferenceController extends BasePreferenceContro
|
||||
mParent = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (savedInstanceState != null) {
|
||||
mOldUsageInfos = savedInstanceState.getParcelableArrayList(KEY_PERMISSION_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putParcelableList(KEY_PERMISSION_USAGE, mOldUsageInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return Boolean.parseBoolean(
|
||||
@@ -92,6 +111,9 @@ public class PermissionBarChartPreferenceController extends BasePreferenceContro
|
||||
.build();
|
||||
|
||||
mBarChartPreference.initializeBarChart(info);
|
||||
if (!mOldUsageInfos.isEmpty()) {
|
||||
mBarChartPreference.setBarViewInfos(createBarViews(mOldUsageInfos));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,7 +122,9 @@ public class PermissionBarChartPreferenceController extends BasePreferenceContro
|
||||
return;
|
||||
}
|
||||
|
||||
mBarChartPreference.updateLoadingState(true /* isLoading */);
|
||||
// We don't hide chart when we have existing data.
|
||||
mBarChartPreference.updateLoadingState(mOldUsageInfos.isEmpty() /* isLoading */);
|
||||
// But we still need to hint user with progress bar that we are updating new usage data.
|
||||
mParent.setLoadingEnabled(true /* enabled */);
|
||||
retrievePermissionUsageData();
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ public class CryptKeeperSettings extends InstrumentedPreferenceFragment {
|
||||
|
||||
if (helper.utils().getKeyguardStoredPasswordQuality(UserHandle.myUserId())
|
||||
== DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
|
||||
showFinalConfirmation(StorageManager.CRYPT_TYPE_DEFAULT, "");
|
||||
showFinalConfirmation(StorageManager.CRYPT_TYPE_DEFAULT, "".getBytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -193,14 +193,14 @@ public class CryptKeeperSettings extends InstrumentedPreferenceFragment {
|
||||
// confirmation prompt; otherwise, go back to the initial state.
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
int type = data.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE, -1);
|
||||
String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
if (!TextUtils.isEmpty(password)) {
|
||||
byte[] password = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
if (!(password == null || password.length == 0)) {
|
||||
showFinalConfirmation(type, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showFinalConfirmation(int type, String password) {
|
||||
private void showFinalConfirmation(int type, byte[] password) {
|
||||
Preference preference = new Preference(getPreferenceManager().getContext());
|
||||
preference.setFragment(CryptKeeperConfirm.class.getName());
|
||||
preference.setTitle(R.string.crypt_keeper_confirm_title);
|
||||
@@ -208,16 +208,16 @@ public class CryptKeeperSettings extends InstrumentedPreferenceFragment {
|
||||
((SettingsActivity) getActivity()).onPreferenceStartFragment(null, preference);
|
||||
}
|
||||
|
||||
private void addEncryptionInfoToPreference(Preference preference, int type, String password) {
|
||||
private void addEncryptionInfoToPreference(Preference preference, int type, byte[] password) {
|
||||
Activity activity = getActivity();
|
||||
DevicePolicyManager dpm = (DevicePolicyManager)
|
||||
activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
if (dpm.getDoNotAskCredentialsOnBoot()) {
|
||||
preference.getExtras().putInt(TYPE, StorageManager.CRYPT_TYPE_DEFAULT);
|
||||
preference.getExtras().putString(PASSWORD, "");
|
||||
preference.getExtras().putByteArray(PASSWORD, "".getBytes());
|
||||
} else {
|
||||
preference.getExtras().putInt(TYPE, type);
|
||||
preference.getExtras().putString(PASSWORD, password);
|
||||
preference.getExtras().putByteArray(PASSWORD, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
|
||||
private RestrictedSwitchPreference mUnifyProfile;
|
||||
|
||||
|
||||
private String mCurrentDevicePassword;
|
||||
private String mCurrentProfilePassword;
|
||||
private byte[] mCurrentDevicePassword;
|
||||
private byte[] mCurrentProfilePassword;
|
||||
private boolean mKeepDeviceLock;
|
||||
|
||||
@Override
|
||||
@@ -151,13 +151,13 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
|
||||
} else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST
|
||||
&& resultCode == Activity.RESULT_OK) {
|
||||
mCurrentDevicePassword =
|
||||
data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
launchConfirmProfileLock();
|
||||
return true;
|
||||
} else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST
|
||||
&& resultCode == Activity.RESULT_OK) {
|
||||
mCurrentProfilePassword =
|
||||
data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
unifyLocks();
|
||||
return true;
|
||||
}
|
||||
@@ -226,7 +226,7 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
|
||||
// PASSWORD_QUALITY_SOMETHING means pattern, everything above means PIN/password.
|
||||
if (profileQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
|
||||
mLockPatternUtils.saveLockPattern(
|
||||
LockPatternUtils.stringToPattern(mCurrentProfilePassword),
|
||||
LockPatternUtils.byteArrayToPattern(mCurrentProfilePassword),
|
||||
mCurrentDevicePassword, MY_USER_ID);
|
||||
} else {
|
||||
mLockPatternUtils.saveLockPassword(
|
||||
|
||||
@@ -18,11 +18,11 @@ package com.android.settings.security;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.display.AmbientDisplayAlwaysOnPreferenceController;
|
||||
|
||||
@@ -17,27 +17,34 @@
|
||||
package com.android.settings.users;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.widget.SwitchWidgetController;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
|
||||
public class MultiUserSwitchBarController implements SwitchWidgetController.OnSwitchChangeListener,
|
||||
LifecycleObserver, OnStart, OnStop {
|
||||
private static final String TAG = "MultiUserSwitchBarCtrl";
|
||||
|
||||
interface OnMultiUserSwitchChangedListener {
|
||||
void onMultiUserSwitchChanged(boolean newState);
|
||||
}
|
||||
@VisibleForTesting
|
||||
final SwitchWidgetController mSwitchBar;
|
||||
|
||||
private static final String TAG = "MultiUserSwitchBarCtrl";
|
||||
private final Context mContext;
|
||||
private final SwitchWidgetController mSwitchBar;
|
||||
private final UserCapabilities mUserCapabilities;
|
||||
private final OnMultiUserSwitchChangedListener mListener;
|
||||
|
||||
|
||||
MultiUserSwitchBarController(Context context, SwitchWidgetController switchBar,
|
||||
OnMultiUserSwitchChangedListener listener) {
|
||||
mContext = context;
|
||||
@@ -45,8 +52,15 @@ public class MultiUserSwitchBarController implements SwitchWidgetController.OnSw
|
||||
mListener = listener;
|
||||
mUserCapabilities = UserCapabilities.create(context);
|
||||
mSwitchBar.setChecked(mUserCapabilities.mUserSwitcherEnabled);
|
||||
mSwitchBar.setEnabled(!mUserCapabilities.mDisallowSwitchUser
|
||||
&& !mUserCapabilities.mIsGuest && mUserCapabilities.isAdmin());
|
||||
|
||||
if (mUserCapabilities.mDisallowSwitchUser) {
|
||||
mSwitchBar.setDisabledByAdmin(RestrictedLockUtilsInternal
|
||||
.checkIfRestrictionEnforced(mContext, UserManager.DISALLOW_USER_SWITCH,
|
||||
UserHandle.myUserId()));
|
||||
} else {
|
||||
mSwitchBar.setEnabled(!mUserCapabilities.mDisallowSwitchUser
|
||||
&& !mUserCapabilities.mIsGuest && mUserCapabilities.isAdmin());
|
||||
}
|
||||
mSwitchBar.setListener(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -376,12 +376,12 @@ public class WifiConfigController implements TextWatcher,
|
||||
}
|
||||
|
||||
WifiInfo info = mAccessPoint.getInfo();
|
||||
if (info != null && info.getTxLinkSpeedMbps() != -1) {
|
||||
if (info != null && info.getTxLinkSpeedMbps() != WifiInfo.LINK_SPEED_UNKNOWN) {
|
||||
addRow(group, R.string.tx_wifi_speed, String.format(
|
||||
res.getString(R.string.tx_link_speed), info.getTxLinkSpeedMbps()));
|
||||
}
|
||||
|
||||
if (info != null && info.getRxLinkSpeedMbps() != -1) {
|
||||
if (info != null && info.getRxLinkSpeedMbps() != WifiInfo.LINK_SPEED_UNKNOWN) {
|
||||
addRow(group, R.string.rx_wifi_speed, String.format(
|
||||
res.getString(R.string.rx_link_speed), info.getRxLinkSpeedMbps()));
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
|
||||
cancelActivity = true;
|
||||
} else {
|
||||
final WifiNetworkConfig connectedConfig = getConnectedWifiNetworkConfigOrNull();
|
||||
if (connectedConfig == null) {
|
||||
if (connectedConfig == null || !connectedConfig.isSupportWifiDpp(this)) {
|
||||
showChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
|
||||
} else {
|
||||
mWifiNetworkConfig = connectedConfig;
|
||||
|
||||
@@ -86,7 +86,7 @@ public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
|
||||
MenuItem menuItem;
|
||||
if (wifiNetworkConfig.isSupportConfiguratorQrCodeScanner(getActivity())) {
|
||||
if (wifiNetworkConfig.isSupportWifiDpp(getActivity())) {
|
||||
menuItem = menu.add(0, Menu.FIRST, 0, R.string.next_label);
|
||||
menuItem.setIcon(R.drawable.ic_scan_24dp);
|
||||
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
|
||||
@@ -212,7 +212,7 @@ public class WifiNetworkConfig {
|
||||
wifiManager.connect(wifiConfiguration, listener);
|
||||
}
|
||||
|
||||
public boolean isSupportConfiguratorQrCodeScanner(Context context) {
|
||||
public boolean isSupportWifiDpp(Context context) {
|
||||
if (!WifiDppUtils.isWifiDppEnabled(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -118,10 +118,19 @@ public class WifiSlice implements CustomSliceable {
|
||||
|
||||
final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(getUri());
|
||||
final List<AccessPoint> results = worker != null ? worker.getResults() : null;
|
||||
final int apCount = results == null ? 0 : results.size();
|
||||
|
||||
// Need a loading text when results are not ready.
|
||||
boolean needLoadingRow = results == null;
|
||||
final int apCount = needLoadingRow ? 0 : results.size();
|
||||
// Need a loading text when results are not ready or out of date.
|
||||
boolean needLoadingRow = true;
|
||||
int index = apCount > 0 && results.get(0).isActive() ? 1 : 0;
|
||||
// This loop checks the existence of reachable APs to determine the validity of the current
|
||||
// AP list.
|
||||
for (; index < apCount; index++) {
|
||||
if (results.get(index).isReachable()) {
|
||||
needLoadingRow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add AP rows
|
||||
final CharSequence placeholder = mContext.getText(R.string.summary_placeholder);
|
||||
|
||||
@@ -21,14 +21,17 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.display.DarkUIPreferenceController;
|
||||
import com.android.settings.testutils.XmlTestUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -47,10 +50,13 @@ public class AccessibilitySettingsTest {
|
||||
"accessibility_content_timeout_preference_fragment";
|
||||
private static final String ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE =
|
||||
"accessibility_control_timeout_preference_fragment";
|
||||
private static final String DARK_UI_MODE_PREFERENCE =
|
||||
"dark_ui_mode_accessibility";
|
||||
|
||||
private Context mContext;
|
||||
private ContentResolver mContentResolver;
|
||||
private AccessibilitySettings mSettings;
|
||||
private UiModeManager mUiModeManager;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
@@ -59,6 +65,7 @@ public class AccessibilitySettingsTest {
|
||||
mContentResolver = mContext.getContentResolver();
|
||||
mSettings = spy(new AccessibilitySettings());
|
||||
doReturn(mContext).when(mSettings).getContext();
|
||||
mUiModeManager = mContext.getSystemService(UiModeManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -146,4 +153,29 @@ public class AccessibilitySettingsTest {
|
||||
|
||||
assertThat(preference.getSummary()).isEqualTo(mContext.getResources().getString(resId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDarkUIModePreferenceSummary_shouldUpdateSummary() {
|
||||
final ListPreference darkUIModePreference = new ListPreference(mContext);
|
||||
final DarkUIPreferenceController mController;
|
||||
doReturn(darkUIModePreference).when(mSettings).findPreference(
|
||||
DARK_UI_MODE_PREFERENCE);
|
||||
mController = new DarkUIPreferenceController(mContext, DARK_UI_MODE_PREFERENCE);
|
||||
final String darkUIModeDescription = modeToDescription(mUiModeManager.getNightMode());
|
||||
darkUIModePreference.setSummary(mController.getSummary());
|
||||
|
||||
assertThat(darkUIModePreference.getSummary()).isEqualTo(darkUIModeDescription);
|
||||
}
|
||||
|
||||
private String modeToDescription(int mode) {
|
||||
String[] values = mContext.getResources().getStringArray(R.array.dark_ui_mode_entries);
|
||||
switch (mode) {
|
||||
case UiModeManager.MODE_NIGHT_YES:
|
||||
return values[0];
|
||||
case UiModeManager.MODE_NIGHT_NO:
|
||||
case UiModeManager.MODE_NIGHT_AUTO:
|
||||
default:
|
||||
return values[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.usage.UsageStats;
|
||||
import android.content.Context;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class AllAppsInfoPreferenceControllerTest {
|
||||
|
||||
private AllAppsInfoPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
mController = new AllAppsInfoPreferenceController(context, "test_key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_hasRecentApps_shouldReturnConditionallyUnavailable() {
|
||||
final List<UsageStats> stats = new ArrayList<>();
|
||||
final UsageStats stat1 = new UsageStats();
|
||||
stat1.mLastTimeUsed = System.currentTimeMillis();
|
||||
stat1.mPackageName = "pkg.class";
|
||||
stats.add(stat1);
|
||||
mController.setRecentApps(stats);
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noRecentApps_shouldReturnAvailable() {
|
||||
// No data
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.applications;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -111,7 +112,6 @@ public class RecentAppsPreferenceControllerTest {
|
||||
|
||||
final View appEntitiesHeaderView = LayoutInflater.from(context).inflate(
|
||||
R.layout.app_entities_header, null /* root */);
|
||||
final Preference seeAllPreference = new Preference(context);
|
||||
final Preference dividerPreference = new Preference(context);
|
||||
mRecentAppsPreference = spy(new LayoutPreference(context, appEntitiesHeaderView));
|
||||
|
||||
@@ -119,11 +119,8 @@ public class RecentAppsPreferenceControllerTest {
|
||||
mController.setFragment(mFragment);
|
||||
mController.mAppEntitiesController = mock(AppEntitiesHeaderController.class);
|
||||
mController.mRecentAppsPreference = mRecentAppsPreference;
|
||||
mController.mAllAppPref = seeAllPreference;
|
||||
mController.mDivider = dividerPreference;
|
||||
|
||||
when(mScreen.findPreference(RecentAppsPreferenceController.KEY_ALL_APP_INFO))
|
||||
.thenReturn(seeAllPreference);
|
||||
when(mScreen.findPreference(RecentAppsPreferenceController.KEY_DIVIDER))
|
||||
.thenReturn(dividerPreference);
|
||||
when(mScreen.findPreference("test_key")).thenReturn(mRecentAppsPreference);
|
||||
@@ -152,9 +149,33 @@ public class RecentAppsPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_noRecentApps_shouldReturnAvailableUnsearchable() {
|
||||
public void getAvailabilityStatus_noRecentApps_shouldReturnConditionallyUnavailable() {
|
||||
// No data
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_powerSaverModeOn_shouldReturnConditionallyUnavailable() {
|
||||
when(mPowerManager.isPowerSaveMode()).thenReturn(true);
|
||||
|
||||
final List<UsageStats> stats = new ArrayList<>();
|
||||
final UsageStats stat1 = new UsageStats();
|
||||
|
||||
stat1.mLastTimeUsed = System.currentTimeMillis();
|
||||
stat1.mPackageName = "pkg.class";
|
||||
stats.add(stat1);
|
||||
|
||||
// stat1, stat2 are valid apps. stat3 is invalid.
|
||||
when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId()))
|
||||
.thenReturn(mAppEntry);
|
||||
when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
|
||||
.thenReturn(new ResolveInfo());
|
||||
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
mAppEntry.info = mApplicationInfo;
|
||||
mController.reloadData();
|
||||
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,25 +199,6 @@ public class RecentAppsPreferenceControllerTest {
|
||||
assertThat(mController.mAppEntitiesController).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_firstLaunch_shouldNotReloadData() {
|
||||
mController.mIsFirstLaunch = true;
|
||||
|
||||
mController.updateState(mRecentAppsPreference);
|
||||
|
||||
verify(mController, never()).reloadData();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_afterFirstLaunch_shouldReloadDataAndRefreshUi() {
|
||||
mController.mIsFirstLaunch = false;
|
||||
|
||||
mController.updateState(mRecentAppsPreference);
|
||||
|
||||
verify(mController).reloadData();
|
||||
verify(mController).refreshUi();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_threeValidRecentOpenAppsSet_setAppEntityThreeTime() {
|
||||
final List<UsageStats> stats = new ArrayList<>();
|
||||
@@ -227,7 +229,7 @@ public class RecentAppsPreferenceControllerTest {
|
||||
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
mAppEntry.info = mApplicationInfo;
|
||||
mController.mIsFirstLaunch = false;
|
||||
mController.reloadData();
|
||||
|
||||
mController.updateState(mRecentAppsPreference);
|
||||
|
||||
@@ -235,7 +237,6 @@ public class RecentAppsPreferenceControllerTest {
|
||||
.setAppEntity(anyInt(), any(AppEntityInfo.class));
|
||||
assertThat(mController.mRecentAppsPreference.isVisible()).isTrue();
|
||||
assertThat(mController.mDivider.isVisible()).isTrue();
|
||||
assertThat(mController.mAllAppPref.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -268,7 +269,7 @@ public class RecentAppsPreferenceControllerTest {
|
||||
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
mAppEntry.info = mApplicationInfo;
|
||||
mController.mIsFirstLaunch = false;
|
||||
mController.reloadData();
|
||||
|
||||
mController.updateState(mRecentAppsPreference);
|
||||
|
||||
@@ -278,35 +279,6 @@ public class RecentAppsPreferenceControllerTest {
|
||||
.setAppEntity(anyInt(), any(AppEntityInfo.class));
|
||||
assertThat(mController.mRecentAppsPreference.isVisible()).isTrue();
|
||||
assertThat(mController.mDivider.isVisible()).isTrue();
|
||||
assertThat(mController.mAllAppPref.isVisible()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_powerSaverModeOn_headerIsNotVisible() {
|
||||
when(mPowerManager.isPowerSaveMode()).thenReturn(true);
|
||||
|
||||
final List<UsageStats> stats = new ArrayList<>();
|
||||
final UsageStats stat1 = new UsageStats();
|
||||
|
||||
stat1.mLastTimeUsed = System.currentTimeMillis();
|
||||
stat1.mPackageName = "pkg.class";
|
||||
stats.add(stat1);
|
||||
|
||||
// stat1, stat2 are valid apps. stat3 is invalid.
|
||||
when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId()))
|
||||
.thenReturn(mAppEntry);
|
||||
when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
|
||||
.thenReturn(new ResolveInfo());
|
||||
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
mAppEntry.info = mApplicationInfo;
|
||||
mController.mIsFirstLaunch = false;
|
||||
|
||||
mController.updateState(mRecentAppsPreference);
|
||||
|
||||
assertThat(mController.mRecentAppsPreference.isVisible()).isFalse();
|
||||
assertThat(mController.mDivider.isVisible()).isFalse();
|
||||
assertThat(mController.mAllAppPref.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -341,7 +313,7 @@ public class RecentAppsPreferenceControllerTest {
|
||||
// Make sure stat2 is considered an instant app.
|
||||
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
|
||||
(InstantAppDataProvider) (ApplicationInfo info) -> info == stat2Entry.info);
|
||||
mController.mIsFirstLaunch = false;
|
||||
mController.reloadData();
|
||||
|
||||
mController.updateState(mRecentAppsPreference);
|
||||
|
||||
@@ -417,7 +389,7 @@ public class RecentAppsPreferenceControllerTest {
|
||||
.thenReturn(new ResolveInfo());
|
||||
when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
|
||||
.thenReturn(stats);
|
||||
mController.mIsFirstLaunch = false;
|
||||
mController.reloadData();
|
||||
|
||||
mController.updateState(mRecentAppsPreference);
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowUtils.class})
|
||||
public class SystemAlertWindowPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private SystemAlertWindowPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new SystemAlertWindowPreferenceController(mContext, "key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void systemAlertWindow_byDefault_shouldBeShown() {
|
||||
ShadowUtils.setIsSystemAlertWindowEnabled(true);
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void systemAlertWindow_lowMemory_shouldNotBeShown() {
|
||||
ShadowUtils.setIsSystemAlertWindowEnabled(false);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,9 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
@@ -29,12 +29,12 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.testutils.shadow.ShadowSecureSettings;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
|
||||
|
||||
@@ -73,14 +73,14 @@ public class BatteryMeterViewTest {
|
||||
public void testSetBatteryInfo_levelLow_setErrorColor() {
|
||||
mBatteryMeterView.setBatteryLevel(BATTERY_LOW_LEVEL);
|
||||
|
||||
verify(mDrawable).setBatteryColorFilter(mErrorColorFilter);
|
||||
verify(mDrawable).setColorFilter(mErrorColorFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBatteryInfo_levelNormal_setNormalColor() {
|
||||
mBatteryMeterView.setBatteryLevel(BATTERY_LEVEL);
|
||||
|
||||
verify(mDrawable).setBatteryColorFilter(mAccentColorFilter);
|
||||
verify(mDrawable).setColorFilter(mAccentColorFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -26,8 +26,8 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
@@ -26,8 +26,8 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
@@ -25,8 +25,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -28,8 +28,8 @@ import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
|
||||
import com.android.internal.hardware.AmbientDisplayConfiguration;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
@@ -33,6 +35,7 @@ import androidx.slice.Slice;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.slices.CustomSliceRegistry;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -52,6 +55,7 @@ public class ContextualCardLoaderTest {
|
||||
private Context mContext;
|
||||
private ContextualCardLoader mContextualCardLoader;
|
||||
private EligibleCardChecker mEligibleCardChecker;
|
||||
private FakeFeatureFactory mFakeFeatureFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -59,6 +63,7 @@ public class ContextualCardLoaderTest {
|
||||
mContextualCardLoader = spy(new ContextualCardLoader(mContext));
|
||||
mEligibleCardChecker =
|
||||
spy(new EligibleCardChecker(mContext, getContextualCard(TEST_SLICE_URI)));
|
||||
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -158,6 +163,26 @@ public class ContextualCardLoaderTest {
|
||||
assertThat(mContextualCardLoader.loadInBackground()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDisplayableCards_refreshCardUri_shouldLogContextualCardDisplay() {
|
||||
mContextualCardLoader.mNotifyUri = CardContentProvider.REFRESH_CARD_URI;
|
||||
|
||||
mContextualCardLoader.getDisplayableCards(new ArrayList<ContextualCard>());
|
||||
|
||||
verify(mFakeFeatureFactory.mContextualCardFeatureProvider).logContextualCardDisplay(
|
||||
any(List.class), any(List.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDisplayableCards_deleteCardUri_shouldNotLogContextualCardDisplay() {
|
||||
mContextualCardLoader.mNotifyUri = CardContentProvider.DELETE_CARD_URI;
|
||||
|
||||
mContextualCardLoader.getDisplayableCards(new ArrayList<ContextualCard>());
|
||||
|
||||
verify(mFakeFeatureFactory.mContextualCardFeatureProvider, never())
|
||||
.logContextualCardDisplay(any(List.class), any(List.class));
|
||||
}
|
||||
|
||||
private ContextualCard getContextualCard(String sliceUri) {
|
||||
return new ContextualCard.Builder()
|
||||
.setName("test_card")
|
||||
|
||||
@@ -75,7 +75,7 @@ public class SliceContextualCardControllerTest {
|
||||
|
||||
@Test
|
||||
public void onDismissed_cardShouldBeMarkedAsDismissed() {
|
||||
final Uri providerUri = CardContentProvider.URI;
|
||||
final Uri providerUri = CardContentProvider.REFRESH_CARD_URI;
|
||||
mResolver.insert(providerUri, generateOneRow());
|
||||
doNothing().when(mController).showFeedbackDialog(any(ContextualCard.class));
|
||||
|
||||
@@ -96,7 +96,7 @@ public class SliceContextualCardControllerTest {
|
||||
|
||||
@Test
|
||||
public void onDismissed_noFeedbackEmail_shouldNotShowFeedbackDialog() {
|
||||
mResolver.insert(CardContentProvider.URI, generateOneRow());
|
||||
mResolver.insert(CardContentProvider.REFRESH_CARD_URI, generateOneRow());
|
||||
final ContextualCardsFragment fragment =
|
||||
FragmentController.of(new ContextualCardsFragment()).create().get();
|
||||
final ShadowActivity shadowActivity = Shadows.shadowOf(fragment.getActivity());
|
||||
@@ -109,7 +109,7 @@ public class SliceContextualCardControllerTest {
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void onDismissed_hasFeedbackEmail_shouldShowFeedbackDialog() {
|
||||
mResolver.insert(CardContentProvider.URI, generateOneRow());
|
||||
mResolver.insert(CardContentProvider.REFRESH_CARD_URI, generateOneRow());
|
||||
final ContextualCardsFragment fragment =
|
||||
FragmentController.of(new ContextualCardsFragment()).create().get();
|
||||
final ShadowActivity shadowActivity = Shadows.shadowOf(fragment.getActivity());
|
||||
|
||||
@@ -87,7 +87,7 @@ public class ChooseLockPasswordTest {
|
||||
@Test
|
||||
public void intentBuilder_setPassword_shouldAddExtras() {
|
||||
Intent intent = new IntentBuilder(application)
|
||||
.setPassword("password")
|
||||
.setPassword("password".getBytes())
|
||||
.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
|
||||
.setUserId(123)
|
||||
.build();
|
||||
@@ -95,9 +95,9 @@ public class ChooseLockPasswordTest {
|
||||
assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true))
|
||||
.named("EXTRA_KEY_HAS_CHALLENGE")
|
||||
.isFalse();
|
||||
assertThat(intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
|
||||
assertThat(intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
|
||||
.named("EXTRA_KEY_PASSWORD")
|
||||
.isEqualTo("password");
|
||||
.isEqualTo("password".getBytes());
|
||||
assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
|
||||
.named("PASSWORD_TYPE_KEY")
|
||||
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
@@ -366,7 +366,9 @@ public class ChooseLockPasswordTest {
|
||||
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
|
||||
ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
|
||||
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
|
||||
int validateResult = fragment.validatePassword(userEnteredPassword);
|
||||
byte[] userEnteredPasswordBytes = userEnteredPassword != null
|
||||
? userEnteredPassword.getBytes() : null;
|
||||
int validateResult = fragment.validatePassword(userEnteredPasswordBytes);
|
||||
String[] messages = fragment.convertErrorCodeToMessages(validateResult);
|
||||
|
||||
assertThat(messages).asList().containsExactly((Object[]) expectedValidationResult);
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ChooseLockPatternTest {
|
||||
@Test
|
||||
public void intentBuilder_setPattern_shouldAddExtras() {
|
||||
Intent intent = new IntentBuilder(application)
|
||||
.setPattern("pattern")
|
||||
.setPattern("pattern".getBytes())
|
||||
.setUserId(123)
|
||||
.build();
|
||||
|
||||
@@ -61,9 +61,9 @@ public class ChooseLockPatternTest {
|
||||
.named("EXTRA_KEY_HAS_CHALLENGE")
|
||||
.isFalse();
|
||||
assertThat(intent
|
||||
.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
|
||||
.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
|
||||
.named("EXTRA_KEY_PASSWORD")
|
||||
.isEqualTo("pattern");
|
||||
.isEqualTo("pattern".getBytes());
|
||||
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
|
||||
.named("EXTRA_USER_ID")
|
||||
.isEqualTo(123);
|
||||
|
||||
@@ -124,6 +124,18 @@ public class PermissionBarChartPreferenceControllerTest {
|
||||
verify(mPreference).initializeBarChart(any(BarChartInfo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_usageInfosSet_shouldSetBarViewInfos() {
|
||||
final RuntimePermissionUsageInfo info1 =
|
||||
new RuntimePermissionUsageInfo("permission 1", 10);
|
||||
mController.mOldUsageInfos.add(info1);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
verify(mPreference).setBarViewInfos(any(BarViewInfo[].class));
|
||||
verify(mPreference).initializeBarChart(any(BarChartInfo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPermissionUsageResult_differentPermissionResultSet_shouldSetBarViewInfos() {
|
||||
final List<RuntimePermissionUsageInfo> infos1 = new ArrayList<>();
|
||||
@@ -159,7 +171,7 @@ public class PermissionBarChartPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_permissionHubEnabled_shouldShowProgressBar() {
|
||||
public void onStart_usageInfosNotSetAndPermissionHubEnabled_shouldShowProgressBar() {
|
||||
DeviceConfig.setProperty(DeviceConfig.Privacy.NAMESPACE,
|
||||
DeviceConfig.Privacy.PROPERTY_PERMISSIONS_HUB_ENABLED, "true", true);
|
||||
mController.displayPreference(mScreen);
|
||||
@@ -170,6 +182,21 @@ public class PermissionBarChartPreferenceControllerTest {
|
||||
verify(mPreference).updateLoadingState(true /* isLoading */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_usageInfosSetAndPermissionHubEnabled_shouldNotUpdatePrefLoadingState() {
|
||||
DeviceConfig.setProperty(DeviceConfig.Privacy.NAMESPACE,
|
||||
DeviceConfig.Privacy.PROPERTY_PERMISSIONS_HUB_ENABLED, "true", true);
|
||||
final RuntimePermissionUsageInfo info1 =
|
||||
new RuntimePermissionUsageInfo("permission 1", 10);
|
||||
mController.mOldUsageInfos.add(info1);
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.onStart();
|
||||
|
||||
verify(mFragment).setLoadingEnabled(true /* enabled */);
|
||||
verify(mPreference).updateLoadingState(false /* isLoading */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_permissionHubDisabled_shouldNotShowProgressBar() {
|
||||
DeviceConfig.setProperty(DeviceConfig.Privacy.NAMESPACE,
|
||||
|
||||
@@ -253,6 +253,18 @@ public class SliceTester {
|
||||
assertThat(hasText(sliceItems, subtitle, null /* hints */)).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert no slice item contains subtitle.
|
||||
*
|
||||
* @param sliceItems All slice items of a Slice.
|
||||
* @param subtitle Subtitle for asserting.
|
||||
*/
|
||||
public static void assertNoSliceItemContainsSubtitle(List<SliceItem> sliceItems,
|
||||
String subtitle) {
|
||||
// Subtitle has no hints
|
||||
assertThat(hasText(sliceItems, subtitle, null /* hints */)).isFalse();
|
||||
}
|
||||
|
||||
private static boolean hasText(List<SliceItem> sliceItems, String text, String hints) {
|
||||
boolean hasText = false;
|
||||
for (SliceItem item : sliceItems) {
|
||||
|
||||
@@ -66,12 +66,12 @@ public class ShadowLockPatternUtils {
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
|
||||
protected byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
|
||||
protected boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.annotation.Resetter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -38,6 +39,8 @@ import java.util.Set;
|
||||
@Implements(value = UserManager.class)
|
||||
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
|
||||
|
||||
private static boolean sIsSupportsMultipleUsers;
|
||||
|
||||
private final List<String> mRestrictions = new ArrayList<>();
|
||||
private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>();
|
||||
private final List<UserInfo> mUserProfileInfos = new ArrayList<>();
|
||||
@@ -50,6 +53,11 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
||||
mUserProfileInfos.add(userInfo);
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sIsSupportsMultipleUsers = false;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected List<UserInfo> getProfiles(@UserIdInt int userHandle) {
|
||||
return mUserProfileInfos;
|
||||
@@ -124,4 +132,13 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
||||
public void setUserSwitcherEnabled(boolean userSwitchEnabled) {
|
||||
mUserSwitchEnabled = userSwitchEnabled;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static boolean supportsMultipleUsers() {
|
||||
return sIsSupportsMultipleUsers;
|
||||
}
|
||||
|
||||
public void setSupportsMultipleUsers(boolean supports) {
|
||||
sIsSupportsMultipleUsers = supports;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public class ShadowUtils {
|
||||
private static boolean sIsDemoUser;
|
||||
private static ComponentName sDeviceOwnerComponentName;
|
||||
private static Map<String, String> sAppNameMap;
|
||||
private static boolean sIsSystemAlertWindowEnabled;
|
||||
|
||||
@Implementation
|
||||
protected static int enforceSameOwner(Context context, int userId) {
|
||||
@@ -113,4 +114,13 @@ public class ShadowUtils {
|
||||
}
|
||||
sAppNameMap.put(packageName, appLabel);
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static boolean isSystemAlertWindowEnabled(Context context) {
|
||||
return sIsSystemAlertWindowEnabled;
|
||||
}
|
||||
|
||||
public static void setIsSystemAlertWindowEnabled(boolean enabled) {
|
||||
sIsSystemAlertWindowEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.users;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
import com.android.settings.widget.SwitchBar;
|
||||
import com.android.settings.widget.SwitchBarController;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowUserManager.class})
|
||||
public class MultiUserSwitchBarControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private ShadowUserManager mUserManager;
|
||||
private SwitchBarController mSwitchBarController;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mUserManager = ShadowUserManager.getShadow();
|
||||
mSwitchBarController = spy(new SwitchBarController(new SwitchBar(mContext)));
|
||||
mUserManager.setSupportsMultipleUsers(true);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowUserManager.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_disallowUserSwitch_shouldSetDisabledByAdmin() {
|
||||
mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
|
||||
UserManager.DISALLOW_USER_SWITCH, true);
|
||||
|
||||
final MultiUserSwitchBarController controller = new MultiUserSwitchBarController(mContext,
|
||||
mSwitchBarController, null);
|
||||
|
||||
verify(mSwitchBarController).setDisabledByAdmin(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_allowUserSwitch_shouldNotSetDisabledByAdmin() {
|
||||
mUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()),
|
||||
UserManager.DISALLOW_USER_SWITCH, false);
|
||||
|
||||
final MultiUserSwitchBarController controller = new MultiUserSwitchBarController(mContext,
|
||||
mSwitchBarController, null);
|
||||
|
||||
verify(mSwitchBarController, never()).setDisabledByAdmin(any());
|
||||
}
|
||||
}
|
||||
@@ -429,7 +429,7 @@ public class WifiDetailPreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
public void linkSpeedPref_shouldNotShowIfNotSet() {
|
||||
when(mockWifiInfo.getTxLinkSpeedMbps()).thenReturn(-1);
|
||||
when(mockWifiInfo.getTxLinkSpeedMbps()).thenReturn(WifiInfo.LINK_SPEED_UNKNOWN);
|
||||
|
||||
displayAndResume();
|
||||
|
||||
@@ -447,7 +447,7 @@ public class WifiDetailPreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
public void rxLinkSpeedPref_shouldNotShowIfNotSet() {
|
||||
when(mockWifiInfo.getRxLinkSpeedMbps()).thenReturn(-1);
|
||||
when(mockWifiInfo.getRxLinkSpeedMbps()).thenReturn(WifiInfo.LINK_SPEED_UNKNOWN);
|
||||
|
||||
displayAndResume();
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import static android.app.slice.SliceItem.FORMAT_SLICE;
|
||||
|
||||
import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
|
||||
import static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;
|
||||
import static com.android.settings.wifi.slice.WifiSlice.WifiScanWorker;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -32,6 +33,8 @@ import static org.mockito.Mockito.verify;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WifiManager;
|
||||
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
@@ -44,24 +47,33 @@ import androidx.slice.core.SliceQuery;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.slices.SliceBackgroundWorker;
|
||||
import com.android.settings.testutils.SliceTester;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class WifiSliceTest {
|
||||
|
||||
private static final String AP1_NAME = "ap1";
|
||||
private static final String AP2_NAME = "ap2";
|
||||
|
||||
private Context mContext;
|
||||
private ContentResolver mResolver;
|
||||
private WifiManager mWifiManager;
|
||||
private WifiSlice mWifiSlice;
|
||||
private WifiSlice.WifiScanWorker mWifiScanWorker;
|
||||
private WifiScanWorker mWifiScanWorker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -75,7 +87,7 @@ public class WifiSliceTest {
|
||||
mWifiManager.setWifiEnabled(true);
|
||||
|
||||
mWifiSlice = new WifiSlice(mContext);
|
||||
mWifiScanWorker = new WifiSlice.WifiScanWorker(mContext, WIFI_SLICE_URI);
|
||||
mWifiScanWorker = new WifiScanWorker(mContext, WIFI_SLICE_URI);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,6 +134,107 @@ public class WifiSliceTest {
|
||||
mContext.getString(R.string.wifi_empty_list_wifi_on));
|
||||
}
|
||||
|
||||
private AccessPoint createAccessPoint(String name, boolean active, boolean reachable) {
|
||||
final AccessPoint accessPoint = mock(AccessPoint.class);
|
||||
doReturn(name).when(accessPoint).getConfigName();
|
||||
doReturn(active).when(accessPoint).isActive();
|
||||
doReturn(reachable).when(accessPoint).isReachable();
|
||||
if (active) {
|
||||
final NetworkInfo networkInfo = mock(NetworkInfo.class);
|
||||
doReturn(networkInfo).when(accessPoint).getNetworkInfo();
|
||||
doReturn(NetworkInfo.State.CONNECTED).when(networkInfo).getState();
|
||||
}
|
||||
return accessPoint;
|
||||
}
|
||||
|
||||
private void setWorkerResults(AccessPoint... accessPoints) {
|
||||
final ArrayList<AccessPoint> results = new ArrayList<>();
|
||||
for (AccessPoint ap : accessPoints) {
|
||||
results.add(ap);
|
||||
}
|
||||
final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(mWifiSlice.getUri());
|
||||
doReturn(results).when(worker).getResults();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSliceBackgroundWorker.class)
|
||||
public void getWifiSlice_noReachableAp_shouldReturnLoadingRow() {
|
||||
setWorkerResults(
|
||||
createAccessPoint(AP1_NAME, false, false),
|
||||
createAccessPoint(AP2_NAME, false, false));
|
||||
final Slice wifiSlice = mWifiSlice.getSlice();
|
||||
|
||||
final List<SliceItem> sliceItems = wifiSlice.getItems();
|
||||
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME);
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP2_NAME);
|
||||
// Has scanning text
|
||||
SliceTester.assertAnySliceItemContainsSubtitle(sliceItems,
|
||||
mContext.getString(R.string.wifi_empty_list_wifi_on));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSliceBackgroundWorker.class)
|
||||
public void getWifiSlice_oneActiveAp_shouldReturnLoadingRow() {
|
||||
setWorkerResults(createAccessPoint(AP1_NAME, true, true));
|
||||
final Slice wifiSlice = mWifiSlice.getSlice();
|
||||
|
||||
final List<SliceItem> sliceItems = wifiSlice.getItems();
|
||||
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME);
|
||||
// Has scanning text
|
||||
SliceTester.assertAnySliceItemContainsSubtitle(sliceItems,
|
||||
mContext.getString(R.string.wifi_empty_list_wifi_on));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSliceBackgroundWorker.class)
|
||||
public void getWifiSlice_oneActiveApAndOneUnreachableAp_shouldReturnLoadingRow() {
|
||||
setWorkerResults(
|
||||
createAccessPoint(AP1_NAME, true, true),
|
||||
createAccessPoint(AP2_NAME, false, false));
|
||||
final Slice wifiSlice = mWifiSlice.getSlice();
|
||||
|
||||
final List<SliceItem> sliceItems = wifiSlice.getItems();
|
||||
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME);
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP2_NAME);
|
||||
// Has scanning text
|
||||
SliceTester.assertAnySliceItemContainsSubtitle(sliceItems,
|
||||
mContext.getString(R.string.wifi_empty_list_wifi_on));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSliceBackgroundWorker.class)
|
||||
public void getWifiSlice_oneReachableAp_shouldNotReturnLoadingRow() {
|
||||
setWorkerResults(createAccessPoint(AP1_NAME, false, true));
|
||||
final Slice wifiSlice = mWifiSlice.getSlice();
|
||||
|
||||
final List<SliceItem> sliceItems = wifiSlice.getItems();
|
||||
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME);
|
||||
// No scanning text
|
||||
SliceTester.assertNoSliceItemContainsSubtitle(sliceItems,
|
||||
mContext.getString(R.string.wifi_empty_list_wifi_on));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowSliceBackgroundWorker.class)
|
||||
public void getWifiSlice_allReachableAps_shouldNotReturnLoadingRow() {
|
||||
setWorkerResults(
|
||||
createAccessPoint(AP1_NAME, false, true),
|
||||
createAccessPoint(AP2_NAME, false, true));
|
||||
final Slice wifiSlice = mWifiSlice.getSlice();
|
||||
|
||||
final List<SliceItem> sliceItems = wifiSlice.getItems();
|
||||
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME);
|
||||
SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP2_NAME);
|
||||
// No scanning text
|
||||
SliceTester.assertNoSliceItemContainsSubtitle(sliceItems,
|
||||
mContext.getString(R.string.wifi_empty_list_wifi_on));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleUriChange_updatesWifi() {
|
||||
final Intent intent = mWifiSlice.getIntent();
|
||||
@@ -146,4 +259,14 @@ public class WifiSliceTest {
|
||||
|
||||
verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
|
||||
}
|
||||
|
||||
@Implements(SliceBackgroundWorker.class)
|
||||
public static class ShadowSliceBackgroundWorker {
|
||||
private static WifiScanWorker mWifiScanWorker = mock(WifiScanWorker.class);
|
||||
|
||||
@Implementation
|
||||
public static SliceBackgroundWorker getInstance(Uri uri) {
|
||||
return mWifiScanWorker;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,9 @@ public class HomepageDisplayTests {
|
||||
"Display",
|
||||
"Sound",
|
||||
"Storage",
|
||||
"Security & location",
|
||||
"Security",
|
||||
"Location",
|
||||
"Privacy",
|
||||
"Accounts",
|
||||
"Accessibility",
|
||||
"System"
|
||||
|
||||
Reference in New Issue
Block a user