Merge "Introduce HdcpCheckingPreferenceController"
diff --git a/src/com/android/settings/applications/DrawOverlayDetails.java b/src/com/android/settings/applications/DrawOverlayDetails.java
index c6f3cc0..78f1c08 100644
--- a/src/com/android/settings/applications/DrawOverlayDetails.java
+++ b/src/com/android/settings/applications/DrawOverlayDetails.java
@@ -29,12 +29,13 @@
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.util.Log;
+import android.view.Window;
+import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateOverlayBridge.OverlayState;
-import com.android.settings.core.TouchOverlayManager;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -60,8 +61,6 @@
private Intent mSettingsIntent;
private OverlayState mOverlayState;
- private TouchOverlayManager mTouchOverlayManager;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -69,7 +68,6 @@
Context context = getActivity();
mOverlayBridge = new AppStateOverlayBridge(context, mState, null);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- mTouchOverlayManager = new TouchOverlayManager(context);
// find preferences
addPreferencesFromResource(R.xml.app_ops_permissions_details);
@@ -92,17 +90,17 @@
}
@Override
- public void onStart() {
- super.onStart();
-
- mTouchOverlayManager.setOverlayAllowed(false);
+ public void onResume() {
+ super.onResume();
+ getActivity().getWindow().addFlags(
+ WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
}
@Override
- public void onStop() {
- super.onStop();
-
- mTouchOverlayManager.setOverlayAllowed(true);
+ public void onPause() {
+ getActivity().getWindow().clearFlags(
+ WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ super.onPause();
}
@Override
@@ -153,16 +151,6 @@
.getMetricsFeatureProvider().action(getContext(), logCategory, packageName);
}
- private boolean canDrawOverlay(String pkgName) {
- int result = mAppOpsManager.noteOpNoThrow(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- mPackageInfo.applicationInfo.uid, pkgName);
- if (result == AppOpsManager.MODE_ALLOWED) {
- return true;
- }
-
- return false;
- }
-
@Override
protected boolean refreshUi() {
mOverlayState = mOverlayBridge.getOverlayInfo(mPackageName,
diff --git a/src/com/android/settings/core/TouchOverlayManager.java b/src/com/android/settings/core/TouchOverlayManager.java
deleted file mode 100644
index f69d1bf..0000000
--- a/src/com/android/settings/core/TouchOverlayManager.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.core;
-
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.os.Binder;
-import android.os.IBinder;
-
-public class TouchOverlayManager {
-
- private final Context mContext;
- private final IBinder mToken = new Binder();
-
- public TouchOverlayManager(Context context) {
- mContext = context;
- }
-
- public void setOverlayAllowed(boolean allowed) {
- final AppOpsManager aom = mContext.getSystemService(AppOpsManager.class);
- if (aom != null) {
- aom.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, !allowed, mToken);
- aom.setUserRestriction(AppOpsManager.OP_TOAST_WINDOW, !allowed, mToken);
- }
- }
-}
diff --git a/src/com/android/settings/development/BugReportPreferenceController.java b/src/com/android/settings/development/BugReportPreferenceController.java
index 015071f..c05dd26 100644
--- a/src/com/android/settings/development/BugReportPreferenceController.java
+++ b/src/com/android/settings/development/BugReportPreferenceController.java
@@ -24,6 +24,10 @@
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
+/**
+ * deprecated in favor of {@link BugReportPreferenceControllerV2}
+ */
+@Deprecated
public class BugReportPreferenceController extends AbstractPreferenceController implements
PreferenceControllerMixin {
diff --git a/src/com/android/settings/development/BugReportPreferenceControllerV2.java b/src/com/android/settings/development/BugReportPreferenceControllerV2.java
new file mode 100644
index 0000000..7df23a6
--- /dev/null
+++ b/src/com/android/settings/development/BugReportPreferenceControllerV2.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 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.development;
+
+import android.content.Context;
+import android.os.UserManager;
+
+public class BugReportPreferenceControllerV2 extends DeveloperOptionsPreferenceController {
+
+ private static final String KEY_BUGREPORT = "bugreport";
+
+ private final UserManager mUserManager;
+
+ public BugReportPreferenceControllerV2(Context context) {
+ super(context);
+
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return !mUserManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_BUGREPORT;
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ // intentional no-op
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ // intentional no-op
+ }
+}
diff --git a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
index 667ae31..b7b2759 100644
--- a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
+++ b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
@@ -23,4 +23,6 @@
int REQUEST_CODE_ENABLE_OEM_UNLOCK = 0;
int REQUEST_CODE_DEBUG_APP = 1;
+
+ int REQUEST_MOCK_LOCATION_APP = 2;
}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 00a2375..a867330 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -245,14 +245,14 @@
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
- // take bug report
+ controllers.add(new BugReportPreferenceControllerV2(context));
controllers.add(new LocalBackupPasswordPreferenceController(context));
controllers.add(new StayAwakePreferenceController(context, lifecycle));
controllers.add(new HdcpCheckingPreferenceController(context));
controllers.add(new BluetoothSnoopLogPreferenceController(context));
controllers.add(new OemUnlockPreferenceController(context, activity, fragment));
// running services
- // convert to file encryption
+ controllers.add(new FileEncryptionPreferenceController(context));
controllers.add(new PictureColorModePreferenceController(context, lifecycle));
controllers.add(new WebViewAppPreferenceControllerV2(context));
controllers.add(new CoolColorTemperaturePreferenceController(context));
@@ -263,7 +263,7 @@
controllers.add(new ClearAdbKeysPreferenceController(context, fragment));
controllers.add(new LocalTerminalPreferenceController(context));
controllers.add(new BugReportInPowerPreferenceControllerV2(context));
- // select mock location app
+ controllers.add(new MockLocationAppPreferenceController(context, fragment));
controllers.add(new DebugViewAttributesPreferenceController(context));
controllers.add(new SelectDebugAppPreferenceController(context, fragment));
controllers.add(new WaitForDebuggerPreferenceController(context));
@@ -320,7 +320,7 @@
// inactive apps
controllers.add(new AllowAppsOnExternalPreferenceController(context));
controllers.add(new ResizableActivityPreferenceController(context));
- // reset shortcutmanager rate-limiting
+ controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/development/FileEncryptionPreferenceController.java b/src/com/android/settings/development/FileEncryptionPreferenceController.java
new file mode 100644
index 0000000..463bb70
--- /dev/null
+++ b/src/com/android/settings/development/FileEncryptionPreferenceController.java
@@ -0,0 +1,105 @@
+/*
+ * 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.development;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.os.storage.IStorageManager;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+
+public class FileEncryptionPreferenceController extends DeveloperOptionsPreferenceController {
+
+ private static final String KEY_CONVERT_FBE = "convert_to_file_encryption";
+ private static final String KEY_STORAGE_MANAGER = "mount";
+
+ @VisibleForTesting
+ static final String FILE_ENCRYPTION_PROPERTY_KEY = "ro.crypto.type";
+
+ private final IStorageManager mStorageManager;
+
+ private Preference mPreference;
+
+ public FileEncryptionPreferenceController(Context context) {
+ super(context);
+
+ mStorageManager = getStorageManager();
+ }
+
+ @Override
+ public boolean isAvailable() {
+ if (mStorageManager == null) {
+ return false;
+ }
+
+ try {
+ return mStorageManager.isConvertibleToFBE();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_CONVERT_FBE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ if (!TextUtils.equals("file",
+ SystemProperties.get(FILE_ENCRYPTION_PROPERTY_KEY, "none" /* default */))) {
+ return;
+ }
+
+ mPreference.setEnabled(false);
+ mPreference.setSummary(
+ mContext.getResources().getString(R.string.convert_to_file_encryption_done));
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ // intentional no-op
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ // intentional no-op
+ }
+
+ private IStorageManager getStorageManager() {
+ try {
+ return IStorageManager.Stub.asInterface(
+ ServiceManager.getService(KEY_STORAGE_MANAGER));
+ } catch (VerifyError e) {
+ // Used for tests since Robolectric cannot initialize this class.
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/development/MockLocationAppPreferenceController.java b/src/com/android/settings/development/MockLocationAppPreferenceController.java
new file mode 100644
index 0000000..9f6c4d3
--- /dev/null
+++ b/src/com/android/settings/development/MockLocationAppPreferenceController.java
@@ -0,0 +1,183 @@
+/*
+ * 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.development;
+
+import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes
+ .REQUEST_MOCK_LOCATION_APP;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settingslib.wrapper.PackageManagerWrapper;
+
+import java.util.List;
+
+public class MockLocationAppPreferenceController extends DeveloperOptionsPreferenceController {
+
+ private static final String MOCK_LOCATION_APP_KEY = "mock_location_app";
+ private static final int[] MOCK_LOCATION_APP_OPS = new int[]{AppOpsManager.OP_MOCK_LOCATION};
+
+ private final DevelopmentSettingsDashboardFragment mFragment;
+ private final AppOpsManager mAppsOpsManager;
+ private final PackageManagerWrapper mPackageManager;
+ private Preference mPreference;
+
+ public MockLocationAppPreferenceController(Context context,
+ DevelopmentSettingsDashboardFragment fragment) {
+ super(context);
+
+ mFragment = fragment;
+ mAppsOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mPackageManager = new PackageManagerWrapper(context.getPackageManager());
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return MOCK_LOCATION_APP_KEY;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+ return false;
+ }
+ final Intent intent = new Intent(mContext, AppPicker.class);
+ intent.putExtra(AppPicker.EXTRA_REQUESTIING_PERMISSION,
+ Manifest.permission.ACCESS_MOCK_LOCATION);
+ mFragment.startActivityForResult(intent, REQUEST_MOCK_LOCATION_APP);
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ updateMockLocation();
+ }
+
+ @Override
+ public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode != REQUEST_MOCK_LOCATION_APP || resultCode != Activity.RESULT_OK) {
+ return false;
+ }
+ writeMockLocation(data.getAction());
+ updateMockLocation();
+ return true;
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ mPreference.setEnabled(true);
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ mPreference.setEnabled(false);
+ }
+
+ private void updateMockLocation() {
+ final String mockLocationApp = getCurrentMockLocationApp();
+
+ if (!TextUtils.isEmpty(mockLocationApp)) {
+ mPreference.setSummary(
+ mContext.getResources().getString(R.string.mock_location_app_set,
+ getAppLabel(mockLocationApp)));
+ } else {
+ mPreference.setSummary(
+ mContext.getResources().getString(R.string.mock_location_app_not_set));
+ }
+ }
+
+ private void writeMockLocation(String mockLocationAppName) {
+ removeAllMockLocations();
+ // Enable the app op of the new mock location app if such.
+ if (!TextUtils.isEmpty(mockLocationAppName)) {
+ try {
+ final ApplicationInfo ai = mPackageManager.getApplicationInfo(
+ mockLocationAppName, PackageManager.MATCH_DISABLED_COMPONENTS);
+ mAppsOpsManager.setMode(AppOpsManager.OP_MOCK_LOCATION, ai.uid,
+ mockLocationAppName, AppOpsManager.MODE_ALLOWED);
+ } catch (PackageManager.NameNotFoundException e) {
+ /* ignore */
+ }
+ }
+ }
+
+ private String getAppLabel(String mockLocationApp) {
+ try {
+ final ApplicationInfo ai = mPackageManager.getApplicationInfo(
+ mockLocationApp, PackageManager.MATCH_DISABLED_COMPONENTS);
+ final CharSequence appLabel = mPackageManager.getApplicationLabel(ai);
+ return appLabel != null ? appLabel.toString() : mockLocationApp;
+ } catch (PackageManager.NameNotFoundException e) {
+ return mockLocationApp;
+ }
+ }
+
+ private void removeAllMockLocations() {
+ // Disable the app op of the previous mock location app if such.
+ final List<AppOpsManager.PackageOps> packageOps = mAppsOpsManager.getPackagesForOps(
+ MOCK_LOCATION_APP_OPS);
+ if (packageOps == null) {
+ return;
+ }
+ // Should be one but in case we are in a bad state due to use of command line tools.
+ for (AppOpsManager.PackageOps packageOp : packageOps) {
+ if (packageOp.getOps().get(0).getMode() != AppOpsManager.MODE_ERRORED) {
+ removeMockLocationForApp(packageOp.getPackageName());
+ }
+ }
+ }
+
+ private void removeMockLocationForApp(String appName) {
+ try {
+ final ApplicationInfo ai = mPackageManager.getApplicationInfo(
+ appName, PackageManager.MATCH_DISABLED_COMPONENTS);
+ mAppsOpsManager.setMode(AppOpsManager.OP_MOCK_LOCATION, ai.uid,
+ appName, AppOpsManager.MODE_ERRORED);
+ } catch (PackageManager.NameNotFoundException e) {
+ /* ignore */
+ }
+ }
+
+ private String getCurrentMockLocationApp() {
+ final List<AppOpsManager.PackageOps> packageOps = mAppsOpsManager.getPackagesForOps(
+ MOCK_LOCATION_APP_OPS);
+ if (packageOps != null) {
+ for (AppOpsManager.PackageOps packageOp : packageOps) {
+ if (packageOp.getOps().get(0).getMode() == AppOpsManager.MODE_ALLOWED) {
+ return packageOps.get(0).getPackageName();
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/settings/development/ShortcutManagerThrottlingPreferenceController.java b/src/com/android/settings/development/ShortcutManagerThrottlingPreferenceController.java
new file mode 100644
index 0000000..c8fdaec
--- /dev/null
+++ b/src/com/android/settings/development/ShortcutManagerThrottlingPreferenceController.java
@@ -0,0 +1,91 @@
+/*
+ * 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.development;
+
+import android.content.Context;
+import android.content.pm.IShortcutService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.support.v7.preference.Preference;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.settings.R;
+
+public class ShortcutManagerThrottlingPreferenceController extends
+ DeveloperOptionsPreferenceController {
+
+ private static final String TAG = "ShortcutMgrPrefCtrl";
+
+ private static final String SHORTCUT_MANAGER_RESET_KEY = "reset_shortcut_manager_throttling";
+
+ private final IShortcutService mShortcutService;
+
+ public ShortcutManagerThrottlingPreferenceController(Context context) {
+ super(context);
+
+ mShortcutService = getShortCutService();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return SHORTCUT_MANAGER_RESET_KEY;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(SHORTCUT_MANAGER_RESET_KEY, preference.getKey())) {
+ return false;
+ }
+ resetShortcutManagerThrottling();
+ return true;
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ // intentional no-op
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ // intentional no-op
+ }
+
+ private void resetShortcutManagerThrottling() {
+ if (mShortcutService == null) {
+ return;
+ }
+ try {
+ mShortcutService.resetThrottling();
+ Toast.makeText(mContext, R.string.reset_shortcut_manager_throttling_complete,
+ Toast.LENGTH_SHORT).show();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to reset rate limiting", e);
+ }
+ }
+
+ private IShortcutService getShortCutService() {
+ try {
+ return IShortcutService.Stub.asInterface(
+ ServiceManager.getService(Context.SHORTCUT_SERVICE));
+ } catch (VerifyError e) {
+ // Used for tests since Robolectric cannot initialize this class.
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/settings/development/featureflags/FeatureFlagPreference.java b/src/com/android/settings/development/featureflags/FeatureFlagPreference.java
new file mode 100644
index 0000000..80851d3
--- /dev/null
+++ b/src/com/android/settings/development/featureflags/FeatureFlagPreference.java
@@ -0,0 +1,45 @@
+/*
+ * 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.development.featureflags;
+
+import android.content.Context;
+import android.support.v14.preference.SwitchPreference;
+import android.util.FeatureFlagUtils;
+
+public class FeatureFlagPreference extends SwitchPreference {
+
+ private final String mKey;
+
+ public FeatureFlagPreference(Context context, String key) {
+ super(context);
+ mKey = key;
+ setKey(key);
+ setTitle(key);
+ setCheckedInternal(FeatureFlagUtils.isEnabled(mKey));
+ }
+
+ @Override
+ public void setChecked(boolean isChecked) {
+ setCheckedInternal(isChecked);
+ FeatureFlagUtils.setEnabled(mKey, isChecked);
+ }
+
+ private void setCheckedInternal(boolean isChecked) {
+ super.setChecked(isChecked);
+ setSummary(Boolean.toString(isChecked));
+ }
+}
diff --git a/src/com/android/settings/development/featureflags/FeatureFlagsDashboard.java b/src/com/android/settings/development/featureflags/FeatureFlagsDashboard.java
index ee2258d..998e431 100644
--- a/src/com/android/settings/development/featureflags/FeatureFlagsDashboard.java
+++ b/src/com/android/settings/development/featureflags/FeatureFlagsDashboard.java
@@ -23,6 +23,7 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
+import java.util.ArrayList;
import java.util.List;
public class FeatureFlagsDashboard extends DashboardFragment {
@@ -51,6 +52,8 @@
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
- return null;
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(new FeatureFlagsPreferenceController(context, getLifecycle()));
+ return controllers;
}
}
diff --git a/src/com/android/settings/development/featureflags/FeatureFlagsPreferenceController.java b/src/com/android/settings/development/featureflags/FeatureFlagsPreferenceController.java
new file mode 100644
index 0000000..7c00591
--- /dev/null
+++ b/src/com/android/settings/development/featureflags/FeatureFlagsPreferenceController.java
@@ -0,0 +1,81 @@
+/*
+ * 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.development.featureflags;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+
+import java.util.Map;
+
+public class FeatureFlagsPreferenceController extends AbstractPreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver, OnStart {
+
+ private PreferenceScreen mScreen;
+
+ public FeatureFlagsPreferenceController(Context context, Lifecycle lifecycle) {
+ super(context);
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return null;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mScreen = screen;
+ }
+
+ @Override
+ public void onStart() {
+ if (mScreen == null) {
+ return;
+ }
+ final Map<String, String> featureMap = FeatureFlagUtils.getAllFeatureFlags();
+ if (featureMap == null) {
+ return;
+ }
+ mScreen.removeAll();
+ final Context prefContext = mScreen.getContext();
+ for (String prefixedFeature : featureMap.keySet()) {
+ if (prefixedFeature.startsWith(FeatureFlagUtils.FFLAG_PREFIX)
+ && !prefixedFeature.startsWith(FeatureFlagUtils.FFLAG_OVERRIDE_PREFIX)) {
+ final String feature = prefixedFeature.substring(
+ FeatureFlagUtils.FFLAG_PREFIX.length());
+ final Preference pref = new FeatureFlagPreference(prefContext, feature);
+ mScreen.addPreference(pref);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java b/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
index b69844d..31b905e 100644
--- a/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
@@ -18,47 +18,19 @@
import android.content.Context;
import android.os.Build;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-import android.text.TextUtils;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.deviceinfo.AbstractSerialNumberPreferenceController;
-public class SerialNumberPreferenceController extends AbstractPreferenceController implements
+/**
+ * Preference controller for displaying device serial number. Wraps {@link Build#getSerial()}.
+ */
+public class SerialNumberPreferenceController extends
+ AbstractSerialNumberPreferenceController implements
PreferenceControllerMixin {
-
- private static final String KEY_SERIAL_NUMBER = "serial_number";
-
- private final String mSerialNumber;
-
public SerialNumberPreferenceController(Context context) {
- this(context, Build.getSerial());
- }
-
- @VisibleForTesting
- SerialNumberPreferenceController(Context context, String serialNumber) {
super(context);
- mSerialNumber = serialNumber;
}
- @Override
- public boolean isAvailable() {
- return !TextUtils.isEmpty(mSerialNumber);
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- final Preference pref = screen.findPreference(KEY_SERIAL_NUMBER);
- if (pref != null) {
- pref.setSummary(mSerialNumber);
- }
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_SERIAL_NUMBER;
- }
+ // This space intentionally left blank
}
diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
index 66e7c44..16d255b 100644
--- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
+++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
@@ -35,15 +35,13 @@
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.SettingsStringUtil;
import android.util.Slog;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.settings.R;
-import com.android.settings.core.TouchOverlayManager;
/** @hide */
public class NotificationAccessConfirmationActivity extends Activity
@@ -54,14 +52,12 @@
private int mUserId;
private ComponentName mComponentName;
- private TouchOverlayManager mTouchOverlayManager;
private NotificationManager mNm;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mTouchOverlayManager = new TouchOverlayManager(this);
mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME);
@@ -87,6 +83,20 @@
getWindow().setCloseOnTouchOutside(false);
}
+ @Override
+ public void onResume() {
+ super.onResume();
+ getWindow().addFlags(
+ WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ }
+
+ @Override
+ public void onPause() {
+ getWindow().clearFlags(
+ WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ super.onPause();
+ }
+
private void onAllow() {
String requiredPermission = Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
try {
@@ -130,16 +140,4 @@
finish();
}
}
-
- @Override
- protected void onResume() {
- super.onResume();
- mTouchOverlayManager.setOverlayAllowed(false);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mTouchOverlayManager.setOverlayAllowed(true);
- }
}
diff --git a/src/com/android/settings/support/SupportDashboardActivity.java b/src/com/android/settings/support/SupportDashboardActivity.java
index 819d5f7..d3fcf9a 100644
--- a/src/com/android/settings/support/SupportDashboardActivity.java
+++ b/src/com/android/settings/support/SupportDashboardActivity.java
@@ -47,8 +47,8 @@
supportFeatureProvider.startSupportV2(this);
} else {
startActivity(new Intent(this, LegacySupportActivity.class));
- finish();
}
+ finish();
}
/**
diff --git a/tests/robotests/src/android/util/FeatureFlagUtils.java b/tests/robotests/src/android/util/FeatureFlagUtils.java
index 6bc0557..500884a 100644
--- a/tests/robotests/src/android/util/FeatureFlagUtils.java
+++ b/tests/robotests/src/android/util/FeatureFlagUtils.java
@@ -19,6 +19,9 @@
import android.os.SystemProperties;
import android.text.TextUtils;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* This class is only needed to get around Robolectric issue.
*/
@@ -43,4 +46,19 @@
value = SystemProperties.get(FFLAG_PREFIX + feature);
return Boolean.parseBoolean(value);
}
+
+ /**
+ * Override feature flag to new state.
+ */
+ public static void setEnabled(String feature, boolean enabled) {
+ SystemProperties.set(FFLAG_OVERRIDE_PREFIX + feature, enabled ? "true" : "false");
+ }
+
+
+ public static Map<String, String> getAllFeatureFlags() {
+ final Map<String, String> features = new HashMap<>();
+ features.put(FFLAG_PREFIX + "abc", "false");
+ features.put(FFLAG_OVERRIDE_PREFIX + "abc", "true");
+ return features;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/applications/DrawOverlayDetailsTest.java b/tests/robotests/src/com/android/settings/applications/DrawOverlayDetailsTest.java
index 6122576..5d20a4c 100644
--- a/tests/robotests/src/com/android/settings/applications/DrawOverlayDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/DrawOverlayDetailsTest.java
@@ -19,52 +19,59 @@
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.nullable;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
+import android.app.Activity;
import android.content.Context;
+import android.view.Window;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
-import com.android.settings.core.TouchOverlayManager;
import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.shadow.ShadowPreferenceFragment;
+import com.android.settings.testutils.shadow.ShadowAppInfoBase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
-import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class DrawOverlayDetailsTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Context mContext;
-
- private FakeFeatureFactory mFeatureFactory;
- private DrawOverlayDetails mFragment;
+ private Activity mActivity;
@Mock
- private TouchOverlayManager mTouchOverlayManager;
+ private Window mWindow;
+
+ private FakeFeatureFactory mFeatureFactory;
+
+ @Spy
+ private DrawOverlayDetails mFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- FakeFeatureFactory.setupForTest(mContext);
- mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
-
- mFragment = new DrawOverlayDetails();
- ReflectionHelpers.setField(mFragment, "mTouchOverlayManager", mTouchOverlayManager);
+ FakeFeatureFactory.setupForTest(mActivity);
+ mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mActivity);
}
@Test
public void logSpecialPermissionChange() {
- mFragment.onAttach(ShadowApplication.getInstance().getApplicationContext());
+ when(mFragment.getContext()).thenReturn(
+ ShadowApplication.getInstance().getApplicationContext());
+
mFragment.logSpecialPermissionChange(true, "app");
verify(mFeatureFactory.metricsFeatureProvider).action(nullable(Context.class),
eq(MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_APPDRAW_ALLOW), eq("app"));
@@ -75,16 +82,17 @@
}
@Test
- @Config(shadows = ShadowPreferenceFragment.class)
- public void onStart_disableOverlay() {
- mFragment.onStart();
- verify(mTouchOverlayManager).setOverlayAllowed(false);
- }
+ @Config(shadows = {ShadowAppInfoBase.class})
+ public void hideNonSystemOverlaysWhenResumed() {
+ when(mFragment.getActivity()).thenReturn(mActivity);
+ when(mActivity.getWindow()).thenReturn(mWindow);
- @Test
- @Config(shadows = ShadowPreferenceFragment.class)
- public void onStop_enableOverlay() {
- mFragment.onStop();
- verify(mTouchOverlayManager).setOverlayAllowed(true);
+ mFragment.onResume();
+ mFragment.onPause();
+
+ InOrder inOrder = Mockito.inOrder(mWindow);
+ inOrder.verify(mWindow).addFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ inOrder.verify(mWindow).clearFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ inOrder.verifyNoMoreInteractions();
}
}
diff --git a/tests/robotests/src/com/android/settings/development/BugReportPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BugReportPreferenceControllerTest.java
index 3b3b482..d705610 100644
--- a/tests/robotests/src/com/android/settings/development/BugReportPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/BugReportPreferenceControllerTest.java
@@ -39,6 +39,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+/**
+ * deprecated in favor of {@link BugReportPreferenceControllerV2}
+ */
+@Deprecated
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class BugReportPreferenceControllerTest {
diff --git a/tests/robotests/src/com/android/settings/development/BugReportPreferenceControllerV2Test.java b/tests/robotests/src/com/android/settings/development/BugReportPreferenceControllerV2Test.java
new file mode 100644
index 0000000..9b4cde6
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/BugReportPreferenceControllerV2Test.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserManager;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BugReportPreferenceControllerV2Test {
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private UserManager mUserManager;
+
+ private BugReportPreferenceControllerV2 mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ mController = new BugReportPreferenceControllerV2(mContext);
+ }
+
+ @Test
+ public void isAvailable_hasDebugRestriction_shouldBeFalse() {
+ when(mUserManager.hasUserRestriction(anyString())).thenReturn(true);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_noDebugRestriction_shouldBeTrue() {
+ when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/FileEncryptionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/FileEncryptionPreferenceControllerTest.java
new file mode 100644
index 0000000..1810b11
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/FileEncryptionPreferenceControllerTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.development;
+
+import static com.android.settings.development.FileEncryptionPreferenceController
+ .FILE_ENCRYPTION_PROPERTY_KEY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.storage.IStorageManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.SettingsShadowSystemProperties;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {SettingsShadowSystemProperties.class})
+public class FileEncryptionPreferenceControllerTest {
+
+ @Mock
+ private Preference mPreference;
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private IStorageManager mStorageManager;
+
+ private Context mContext;
+ private FileEncryptionPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new FileEncryptionPreferenceController(mContext);
+ when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
+ mPreference);
+ }
+
+ @After
+ public void teardown() {
+ SettingsShadowSystemProperties.clear();
+ }
+
+ @Test
+ public void isAvailable_storageManagerNull_shouldBeFalse() {
+ ReflectionHelpers.setField(mController, "mStorageManager", null);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_notConvertibleToFBE_shouldBeFalse() throws RemoteException {
+ ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
+ when(mStorageManager.isConvertibleToFBE()).thenReturn(false);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_convertibleToFBE_shouldBeTrue() throws RemoteException {
+ ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
+ when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void updateState_settingIsNotFile_shouldDoNothing() throws RemoteException {
+ ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
+ when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
+ mController.displayPreference(mPreferenceScreen);
+ SystemProperties.set(FILE_ENCRYPTION_PROPERTY_KEY, "foobar");
+
+ mController.updateState(mPreference);
+
+ verify(mPreference, never()).setEnabled(anyBoolean());
+ verify(mPreference, never()).setSummary(anyString());
+ }
+
+ @Test
+ public void updateState_settingIsFile_shouldSetSummaryAndDisablePreference()
+ throws RemoteException {
+ ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
+ when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
+ mController.displayPreference(mPreferenceScreen);
+ SystemProperties.set(FILE_ENCRYPTION_PROPERTY_KEY, "file");
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setEnabled(false);
+ verify(mPreference).setSummary(
+ mContext.getResources().getString(R.string.convert_to_file_encryption_done));
+ }
+}
+
+
diff --git a/tests/robotests/src/com/android/settings/development/MockLocationAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/MockLocationAppPreferenceControllerTest.java
new file mode 100644
index 0000000..0aab0db
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/MockLocationAppPreferenceControllerTest.java
@@ -0,0 +1,166 @@
+package com.android.settings.development;
+
+import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes
+ .REQUEST_MOCK_LOCATION_APP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.wrapper.PackageManagerWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.Collections;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class MockLocationAppPreferenceControllerTest {
+
+ @Mock
+ private DevelopmentSettingsDashboardFragment mFragment;
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private PackageManagerWrapper mPackageManager;
+ @Mock
+ private Preference mPreference;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private AppOpsManager.PackageOps mPackageOps;
+ @Mock
+ private AppOpsManager.OpEntry mOpEntry;
+ @Mock
+ private ApplicationInfo mApplicationInfo;
+
+ private Context mContext;
+ private MockLocationAppPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = spy(new MockLocationAppPreferenceController(mContext, mFragment));
+ ReflectionHelpers.setField(mController, "mAppsOpsManager", mAppOpsManager);
+ ReflectionHelpers.setField(mController, "mPackageManager", mPackageManager);
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+ }
+
+ @Test
+ public void updateState_foobarAppSelected_shouldSetSummaryToFoobar() {
+ final String appName = "foobar";
+ when(mAppOpsManager.getPackagesForOps(any())).thenReturn(
+ Collections.singletonList(mPackageOps));
+ when(mPackageOps.getOps()).thenReturn(Collections.singletonList(mOpEntry));
+ when(mOpEntry.getMode()).thenReturn(AppOpsManager.MODE_ALLOWED);
+ when(mPackageOps.getPackageName()).thenReturn(appName);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setSummary(
+ mContext.getResources().getString(R.string.mock_location_app_set, appName));
+ }
+
+ @Test
+ public void updateState_noAppSelected_shouldSetSummaryToDefault() {
+ when(mAppOpsManager.getPackagesForOps(any())).thenReturn(
+ Collections.emptyList());
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setSummary(
+ mContext.getResources().getString(R.string.mock_location_app_not_set));
+ }
+
+ @Test
+ public void onActivityResult_fooPrevAppBarNewApp_shouldRemoveFooAndSetBarAsMockLocationApp()
+ throws PackageManager.NameNotFoundException {
+ final String prevAppName = "foo";
+ final String newAppName = "bar";
+ final Intent intent = new Intent();
+ intent.setAction(newAppName);
+ when(mAppOpsManager.getPackagesForOps(any())).thenReturn(
+ Collections.singletonList(mPackageOps));
+ when(mPackageOps.getOps()).thenReturn(Collections.singletonList(mOpEntry));
+ when(mOpEntry.getMode()).thenReturn(AppOpsManager.MODE_ALLOWED);
+ when(mPackageOps.getPackageName()).thenReturn(prevAppName);
+ when(mPackageManager.getApplicationInfo(anyString(),
+ eq(PackageManager.MATCH_DISABLED_COMPONENTS))).thenReturn(mApplicationInfo);
+
+ final boolean handled = mController.onActivityResult(REQUEST_MOCK_LOCATION_APP,
+ Activity.RESULT_OK, intent);
+
+ assertThat(handled).isTrue();
+ verify(mAppOpsManager).setMode(anyInt(), anyInt(), eq(newAppName),
+ eq(AppOpsManager.MODE_ALLOWED));
+ verify(mAppOpsManager).setMode(anyInt(), anyInt(), eq(prevAppName),
+ eq(AppOpsManager.MODE_ERRORED));
+ }
+
+ @Test
+ public void onActivityResult_incorrectCode_shouldReturnFalse() {
+ final boolean handled = mController.onActivityResult(30983150 /* request code */,
+ Activity.RESULT_OK, null /* intent */);
+
+ assertThat(handled).isFalse();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_samePreferenceKey_shouldLaunchActivity() {
+ final String preferenceKey = mController.getPreferenceKey();
+ when(mPreference.getKey()).thenReturn(preferenceKey);
+
+ final boolean handled = mController.handlePreferenceTreeClick(mPreference);
+
+ assertThat(handled).isTrue();
+ verify(mFragment).startActivityForResult(any(), eq(REQUEST_MOCK_LOCATION_APP));
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_incorrectPreferenceKey_shouldReturnFalse() {
+ when(mPreference.getKey()).thenReturn("SomeRandomKey");
+
+ assertThat(mController.handlePreferenceTreeClick(mPreference)).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
+ mController.onDeveloperOptionsSwitchDisabled();
+
+ verify(mPreference).setEnabled(false);
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchEnabled_shouldEnablePreference() {
+ mController.onDeveloperOptionsSwitchEnabled();
+
+ verify(mPreference).setEnabled(true);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/ShortcutManagerThrottlingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ShortcutManagerThrottlingPreferenceControllerTest.java
new file mode 100644
index 0000000..0a189cb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/ShortcutManagerThrottlingPreferenceControllerTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.IShortcutService;
+import android.os.RemoteException;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ShortcutManagerThrottlingPreferenceControllerTest {
+
+ @Mock
+ private SwitchPreference mPreference;
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private IShortcutService mShortcutService;
+
+ private Context mContext;
+ private ShortcutManagerThrottlingPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new ShortcutManagerThrottlingPreferenceController(mContext);
+ ReflectionHelpers.setField(mController, "mShortcutService", mShortcutService);
+ when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
+ mPreference);
+ mController.displayPreference(mPreferenceScreen);
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_differentPreferenceKey_shouldReturnFalse() {
+ when(mPreference.getKey()).thenReturn("SomeRandomKey");
+
+ assertThat(mController.handlePreferenceTreeClick(mPreference)).isFalse();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_correctPreferenceKey_shouldResetThrottling()
+ throws RemoteException {
+ when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
+
+ final boolean handled = mController.handlePreferenceTreeClick(mPreference);
+
+ assertThat(handled).isTrue();
+ verify(mShortcutService).resetThrottling();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/featureflags/FeatureFlagPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/featureflags/FeatureFlagPreferenceControllerTest.java
new file mode 100644
index 0000000..3d95cf4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/featureflags/FeatureFlagPreferenceControllerTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.development.featureflags;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class FeatureFlagPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mScreen;
+ private Context mContext;
+ private Lifecycle mLifecycle;
+ private FeatureFlagsPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mLifecycle = new Lifecycle();
+ mController = new FeatureFlagsPreferenceController(mContext, mLifecycle);
+ when(mScreen.getContext()).thenReturn(mContext);
+ mController.displayPreference(mScreen);
+ }
+
+ @Test
+ public void verifyConstants() {
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.getPreferenceKey()).isNull();
+ }
+
+ @Test
+ public void onStart_shouldRefreshFeatureFlags() {
+ mLifecycle.onStart();
+
+ verify(mScreen).removeAll();
+ verify(mScreen).addPreference(any(FeatureFlagPreference.class));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/featureflags/FeatureFlagPreferenceTest.java b/tests/robotests/src/com/android/settings/development/featureflags/FeatureFlagPreferenceTest.java
new file mode 100644
index 0000000..11099b1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/featureflags/FeatureFlagPreferenceTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.development.featureflags;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class FeatureFlagPreferenceTest {
+
+ private static final String KEY = "feature_key";
+
+ private Context mContext;
+ private FeatureFlagPreference mPreference;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mPreference = new FeatureFlagPreference(mContext, KEY);
+ }
+
+ @Test
+ public void constructor_shouldSetTitleAndSummary() {
+ assertThat(mPreference.getTitle()).isEqualTo(KEY);
+ assertThat(mPreference.getSummary()).isEqualTo("false");
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void toggle_shouldUpdateSummary() {
+ mPreference.setChecked(true);
+
+ assertThat(mPreference.getSummary()).isEqualTo("true");
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/SerialNumberPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/SerialNumberPreferenceControllerTest.java
deleted file mode 100644
index 18ef003..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/SerialNumberPreferenceControllerTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2016 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.deviceinfo;
-
-import android.content.Context;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.TestConfig;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Answers.RETURNS_DEEP_STUBS;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class SerialNumberPreferenceControllerTest {
-
- @Mock(answer = RETURNS_DEEP_STUBS)
- private Context mContext;
- @Mock(answer = RETURNS_DEEP_STUBS)
- private PreferenceScreen mScreen;
-
- private SerialNumberPreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testIsAvaiable_noSerial_shouldReturnFalse() {
- mController = new SerialNumberPreferenceController(mContext, null);
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void testIsAvaiable_hasSerial_shouldReturnTrue() {
- mController = new SerialNumberPreferenceController(mContext, "123");
-
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void testDisplay_noSerial_shouldHidePreference() {
- final Preference preference = mock(Preference.class);
- when(mScreen.getPreferenceCount()).thenReturn(1);
- when(mScreen.getPreference(0)).thenReturn(preference);
- mController = new SerialNumberPreferenceController(mContext, null);
- when(preference.getKey()).thenReturn(mController.getPreferenceKey());
-
- mController.displayPreference(mScreen);
-
- verify(mScreen).removePreference(any(Preference.class));
- }
-
- @Test
- public void testDisplay_hasSerial_shouldSummary() {
- final String serial = "123";
- final Preference preference = mock(Preference.class);
- when(mScreen.findPreference(anyString())).thenReturn(preference);
-
- mController = new SerialNumberPreferenceController(mContext, serial);
- mController.displayPreference(mScreen);
-
- verify(mScreen, never()).removePreference(any(Preference.class));
- verify(preference).setSummary(serial);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPreferenceFragment.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAppInfoBase.java
similarity index 81%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowPreferenceFragment.java
rename to tests/robotests/src/com/android/settings/testutils/shadow/ShadowAppInfoBase.java
index cfd0ce9..12173c8 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPreferenceFragment.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAppInfoBase.java
@@ -16,20 +16,20 @@
package com.android.settings.testutils.shadow;
-import android.support.v14.preference.PreferenceFragment;
+import com.android.settings.applications.AppInfoBase;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
-@Implements(PreferenceFragment.class)
-public class ShadowPreferenceFragment {
+@Implements(AppInfoBase.class)
+public class ShadowAppInfoBase {
@Implementation
- public void onStart() {
+ public void onResume() {
// No-op.
}
@Implementation
- public void onStop() {
+ public void onPause() {
// No-op.
}
}