Merge "Changed Night display strings to "Night Light""
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 81b2524..10c0bc2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -727,6 +727,14 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.ZEN_MODE_AUTOMATION_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.ACTION_CONDITION_PROVIDER_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.ZenModeSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
@@ -759,25 +767,6 @@
android:value="true" />
</activity>
- <activity android:name="Settings$ZenModeAutomationSettingsActivity"
- android:label="@string/zen_mode_automation_settings_title"
- android:icon="@drawable/ic_settings_notifications"
- android:exported="true"
- android:taskAffinity="">
- <intent-filter android:priority="1">
- <action android:name="android.settings.ZEN_MODE_AUTOMATION_SETTINGS" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- <intent-filter android:priority="1">
- <action android:name="android.settings.ACTION_CONDITION_PROVIDER_SETTINGS" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.notification.ZenModeAutomationSettings" />
- <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
- android:value="true" />
- </activity>
-
<activity android:name="Settings$ZenModeAutomationSuggestionActivity"
android:label="@string/zen_mode_automation_settings_title"
android:icon="@drawable/ic_settings_notifications"
diff --git a/res/layout/instant_app_buttons.xml b/res/layout/instant_app_buttons.xml
new file mode 100644
index 0000000..b267361
--- /dev/null
+++ b/res/layout/instant_app_buttons.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/instant_app_button_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:visibility="gone">
+ <Button
+ android:id="@+id/install"
+ style="@style/AppActionPrimaryButton"
+ android:enabled="false"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/install_text"/>
+ <Button
+ android:id="@+id/clear_data"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/clear_instant_app_data"/>
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f5ac227..9f77998 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6418,7 +6418,7 @@
<!-- Do not disturb: Title for the Priority interruptions option and associated settings page. [CHAR LIMIT=30] -->
<string name="zen_mode_priority_settings_title">Priority only allows</string>
- <!-- Do not disturb: Title for the zen mode automation option and associated settings page. [CHAR LIMIT=30] -->
+ <!-- Do not disturb: Title for the zen mode automation listing. [CHAR LIMIT=30] -->
<string name="zen_mode_automation_settings_title">Automatic rules</string>
<!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=30] -->
@@ -7893,9 +7893,6 @@
<!-- Name of the setting to disable the automatic update -->
<string name="ota_disable_automatic_update">Automatic system updates</string>
- <!-- Name of the setting to enable hal binderization -->
- <string name="enable_hal_binderization">Binderized HALs (requires reboot)</string>
-
<!-- Label for category for data usage [CHAR LIMIT=30] -->
<string name="usage">Usage</string>
@@ -8593,6 +8590,9 @@
<string name="storage_percent_full">full</string>
+ <!-- Label for button allow user to clear the data for an instant app -->
+ <string name="clear_instant_app_data">Clear app</string>
+
<!-- Title of games app storage screen [CHAR LIMIT=30] -->
<string name="game_storage_settings">Games</string>
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index 6ed8dc9..e870539 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -90,10 +90,6 @@
android:summary="@string/color_temperature_desc" />
<SwitchPreference
- android:key="enable_hal_binderization"
- android:title="@string/enable_hal_binderization" />
-
- <SwitchPreference
android:key="ota_disable_automatic_update"
android:title="@string/ota_disable_automatic_update" />
diff --git a/res/xml/installed_app_details_ia.xml b/res/xml/installed_app_details_ia.xml
index 3e06e39..50d183d 100644
--- a/res/xml/installed_app_details_ia.xml
+++ b/res/xml/installed_app_details_ia.xml
@@ -24,10 +24,16 @@
android:order="-10000"/>
<com.android.settings.applications.LayoutPreference
+ android:key="instant_app_buttons"
+ android:layout="@layout/instant_app_buttons"
+ android:selectable="false"
+ android:order="-9999"/>
+
+ <com.android.settings.applications.LayoutPreference
android:key="action_buttons"
android:layout="@layout/app_action_buttons"
android:selectable="false"
- android:order="-9999"/>
+ android:order="-9998"/>
<Preference
android:key="notification_settings"
diff --git a/res/xml/storage_profile_fragment.xml b/res/xml/storage_profile_fragment.xml
index c675744..98cb1dc 100644
--- a/res/xml/storage_profile_fragment.xml
+++ b/res/xml/storage_profile_fragment.xml
@@ -20,22 +20,27 @@
android:title="@string/storage_settings">
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_photos_videos"
- android:title="@string/storage_photos_videos">
- </com.android.settings.deviceinfo.StorageItemPreference>
+ android:title="@string/storage_photos_videos"
+ android:icon="@drawable/ic_photo_library_vd_theme_24"
+ android:order="2" />
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_music_audio"
- android:title="@string/storage_music_audio">
- </com.android.settings.deviceinfo.StorageItemPreference>
+ android:title="@string/storage_music_audio"
+ android:icon="@drawable/ic_music_note_vd_theme_24"
+ android:order="3" />
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_games"
- android:title="@string/storage_games">
- </com.android.settings.deviceinfo.StorageItemPreference>
+ android:title="@string/storage_games"
+ android:icon="@drawable/ic_videogame_vd_theme_24"
+ android:order="4" />
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_other_apps"
- android:title="@string/storage_other_apps">
- </com.android.settings.deviceinfo.StorageItemPreference>
+ android:title="@string/storage_other_apps"
+ android:icon="@drawable/ic_apps_vd_theme_24"
+ android:order="5" />
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_files"
- android:title="@string/storage_files">
- </com.android.settings.deviceinfo.StorageItemPreference>
+ android:title="@string/storage_files"
+ android:icon="@drawable/ic_folder_vd_theme_24"
+ android:order="6" />
</PreferenceScreen>
diff --git a/res/xml/zen_mode_automation_settings.xml b/res/xml/zen_mode_automation_settings.xml
deleted file mode 100644
index 7cfffd4..0000000
--- a/res/xml/zen_mode_automation_settings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:key="zen_mode_settings"
- android:title="@string/zen_mode_automation_settings_title" >
-
- <!-- Rules added at runtime -->
-</PreferenceScreen>
diff --git a/res/xml/zen_mode_settings.xml b/res/xml/zen_mode_settings.xml
index b22ad6a..5fc72aa 100644
--- a/res/xml/zen_mode_settings.xml
+++ b/res/xml/zen_mode_settings.xml
@@ -25,15 +25,14 @@
android:title="@string/zen_mode_priority_settings_title"
android:fragment="com.android.settings.notification.ZenModePrioritySettings" />
- <!-- Automated rules -->
- <Preference
- android:key="automation_settings"
- android:title="@string/zen_mode_automation_settings_title"
- android:fragment="com.android.settings.notification.ZenModeAutomationSettings" />
-
<!-- Visual interruptions -->
<Preference
android:key="visual_interruptions_settings"
android:title="@string/zen_mode_visual_interruptions_settings_title"
android:fragment="com.android.settings.notification.ZenModeVisualInterruptionSettings" />
+
+ <!-- Automatic rules -->
+ <PreferenceCategory
+ android:key="automatic_rules"
+ android:title="@string/zen_mode_automation_settings_title" />
</PreferenceScreen>
diff --git a/src/com/android/settings/applications/AppStoreUtil.java b/src/com/android/settings/applications/AppStoreUtil.java
new file mode 100644
index 0000000..f9b95b0
--- /dev/null
+++ b/src/com/android/settings/applications/AppStoreUtil.java
@@ -0,0 +1,70 @@
+/*
+ * 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;
+
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+
+// This class provides methods that help dealing with app stores.
+public class AppStoreUtil {
+ private static final String LOG_TAG = "AppStoreUtil";
+
+ private static Intent resolveIntent(Context context, Intent i) {
+ ResolveInfo result = context.getPackageManager().resolveActivity(i, 0);
+ return result != null ? new Intent(i.getAction())
+ .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
+ }
+
+ // Returns the package name of the app which installed a given packageName, if one is
+ // available.
+ public static String getInstallerPackageName(Context context, String packageName) {
+ String installerPackageName = null;
+ try {
+ installerPackageName =
+ context.getPackageManager().getInstallerPackageName(packageName);
+ } catch (IllegalArgumentException e) {
+ Log.e(LOG_TAG, "Exception while retrieving the package installer of " + packageName, e);
+ }
+ if (installerPackageName == null) {
+ return null;
+ }
+ return installerPackageName;
+ }
+
+ // Returns a link to the installer app store for a given package name.
+ public static Intent getAppStoreLink(Context context, String installerPackageName,
+ String packageName) {
+ Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
+ .setPackage(installerPackageName);
+ final Intent result = resolveIntent(context, intent);
+ if (result != null) {
+ result.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ return result;
+ }
+ return null;
+ }
+
+ // Convenience method that looks up the installerPackageName for you.
+ public static Intent getAppStoreLink(Context context, String packageName) {
+ String installerPackageName = getInstallerPackageName(context, packageName);
+ return getAppStoreLink(context, installerPackageName, packageName);
+ }
+}
diff --git a/src/com/android/settings/applications/ApplicationFeatureProvider.java b/src/com/android/settings/applications/ApplicationFeatureProvider.java
index 1855308..1816793 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProvider.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProvider.java
@@ -16,6 +16,8 @@
package com.android.settings.applications;
+import com.android.settings.applications.instantapps.InstantAppButtonsController;
+
import android.app.Fragment;
import android.content.Intent;
import android.view.View;
@@ -30,6 +32,14 @@
AppHeaderController newAppHeaderController(Fragment fragment, View appHeader);
/**
+ *
+ * Returns a new {@link InstantAppButtonsController} instance for showing buttons
+ * only relevant to instant apps.
+ */
+ InstantAppButtonsController newInstantAppButtonsController(Fragment fragment,
+ View view);
+
+ /**
* Calculates the total number of apps installed on the device via policy across all users
* and managed profiles.
*
diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
index ca19dca..7cc899b 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
@@ -29,6 +29,7 @@
import android.util.ArraySet;
import android.view.View;
+import com.android.settings.applications.instantapps.InstantAppButtonsController;
import com.android.settings.enterprise.DevicePolicyManagerWrapper;
import java.util.List;
@@ -57,6 +58,12 @@
}
@Override
+ public InstantAppButtonsController newInstantAppButtonsController(Fragment fragment,
+ View view) {
+ return new InstantAppButtonsController(mContext, fragment, view);
+ }
+
+ @Override
public void calculateNumberOfPolicyInstalledApps(boolean async, NumberOfAppsCallback callback) {
final AllUserPolicyInstalledAppCounter counter =
new AllUserPolicyInstalledAppCounter(mContext, mPm, callback);
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index dac10e7..828eca6 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -146,6 +146,7 @@
private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
private static final String KEY_HEADER = "header_view";
+ private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
private static final String KEY_ACTION_BUTTONS = "action_buttons";
private static final String KEY_NOTIFICATION = "notification_settings";
private static final String KEY_STORAGE = "storage_settings";
@@ -222,13 +223,7 @@
if (isBundled) {
enabled = handleDisableable(mUninstallButton);
} else {
- if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0
- && mUserManager.getUsers().size() >= 2) {
- // When we have multiple users, there is a separate menu
- // to uninstall for all users.
- enabled = false;
- }
- mUninstallButton.setText(R.string.uninstall_text);
+ enabled = initUnintsallButtonForUserApp();
}
// If this is a device admin, it can't be uninstalled or disabled.
// We do this here so the text of the button is still set correctly.
@@ -298,6 +293,22 @@
}
}
+ @VisibleForTesting
+ boolean initUnintsallButtonForUserApp() {
+ boolean enabled = true;
+ if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0
+ && mUserManager.getUsers().size() >= 2) {
+ // When we have multiple users, there is a separate menu
+ // to uninstall for all users.
+ enabled = false;
+ } else if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
+ enabled = false;
+ mUninstallButton.setVisibility(View.GONE);
+ }
+ mUninstallButton.setText(R.string.uninstall_text);
+ return enabled;
+ }
+
/** Returns if the supplied package is device owner or profile owner of at least one user */
private boolean isProfileOrDeviceOwner(String packageName) {
List<UserInfo> userInfos = mUserManager.getUsers();
@@ -455,12 +466,6 @@
mForceStopButton.setEnabled(false);
}
- private Intent resolveIntent(Intent i) {
- ResolveInfo result = getContext().getPackageManager().resolveActivity(i, 0);
- return result != null ? new Intent(i.getAction())
- .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
- }
-
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset)
@@ -570,6 +575,8 @@
} else if (PackageUtil.countPackageInUsers(mPm, mUserManager, mPackageName) < 2
&& (appEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
showIt = false;
+ } else if (AppUtils.isInstant(appEntry.info)) {
+ showIt = false;
}
return showIt;
}
@@ -800,11 +807,15 @@
}
}
- private void checkForceStop() {
+ @VisibleForTesting
+ void checkForceStop() {
if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
// User can't force stop device admin.
Log.w(LOG_TAG, "User can't force stop device admin");
updateForceStopButton(false);
+ } else if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
+ updateForceStopButton(false);
+ mForceStopButton.setVisibility(View.GONE);
} else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) {
// If the app isn't explicitly stopped, then always show the
// force stop button.
@@ -1064,6 +1075,7 @@
}
addAppInstallerInfoPref(screen);
+ maybeAddInstantAppButtons();
}
private boolean isPotentialAppSource() {
@@ -1074,16 +1086,9 @@
}
private void addAppInstallerInfoPref(PreferenceScreen screen) {
- String installerPackageName = null;
- try {
- installerPackageName =
- getContext().getPackageManager().getInstallerPackageName(mPackageName);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Exception while retrieving the package installer of " + mPackageName, e);
- }
- if (installerPackageName == null) {
- return;
- }
+ String installerPackageName =
+ AppStoreUtil.getInstallerPackageName(getContext(), mPackageName);
+
final CharSequence installerLabel = Utils.getApplicationLabel(getContext(),
installerPackageName);
if (installerLabel == null) {
@@ -1096,18 +1101,31 @@
pref.setTitle(R.string.app_install_details_title);
pref.setKey("app_info_store");
pref.setSummary(getString(R.string.app_install_details_summary, installerLabel));
- final Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
- .setPackage(installerPackageName);
- final Intent result = resolveIntent(intent);
- if (result != null) {
- result.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName);
- pref.setIntent(result);
+
+ Intent intent =
+ AppStoreUtil.getAppStoreLink(getContext(), installerPackageName, mPackageName);
+ if (intent != null) {
+ pref.setIntent(intent);
} else {
pref.setEnabled(false);
}
category.addPreference(pref);
}
+ @VisibleForTesting
+ void maybeAddInstantAppButtons() {
+ if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
+ LayoutPreference buttons = (LayoutPreference) findPreference(KEY_INSTANT_APP_BUTTONS);
+ final Activity activity = getActivity();
+ FeatureFactory.getFactory(activity)
+ .getApplicationFeatureProvider(activity)
+ .newInstantAppButtonsController(this,
+ buttons.findViewById(R.id.instant_app_button_container))
+ .setPackageName(mPackageName)
+ .show();
+ }
+ }
+
private boolean hasPermission(String permission) {
if (mPackageInfo == null || mPackageInfo.requestedPermissions == null) {
return false;
diff --git a/src/com/android/settings/applications/instantapps/InstantAppButtonsController.java b/src/com/android/settings/applications/instantapps/InstantAppButtonsController.java
new file mode 100644
index 0000000..aa7c418
--- /dev/null
+++ b/src/com/android/settings/applications/instantapps/InstantAppButtonsController.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.applications.instantapps;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.applications.AppStoreUtil;
+import com.android.settings.overlay.FeatureFactory;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+/** Encapsulates a container for buttons relevant to instant apps */
+public class InstantAppButtonsController {
+
+ private final Context mContext;
+ private final Fragment mFragment;
+ private final View mView;
+ private String mPackageName;
+
+ public InstantAppButtonsController(Context context, Fragment fragment, View view) {
+ mContext = context;
+ mFragment = fragment;
+ mView = view;
+ }
+
+ public InstantAppButtonsController setPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ public void bindButtons() {
+ Button installButton = (Button)mView.findViewById(R.id.install);
+ Button clearDataButton = (Button)mView.findViewById(R.id.clear_data);
+ Intent installIntent = AppStoreUtil.getAppStoreLink(mContext, mPackageName);
+ if (installIntent != null) {
+ installButton.setEnabled(true);
+ installButton.setOnClickListener(v -> mFragment.startActivity(installIntent));
+ }
+ clearDataButton.setOnClickListener(v -> {
+ FeatureFactory.getFactory(mContext).getMetricsFeatureProvider().action(mContext,
+ MetricsEvent.ACTION_SETTINGS_CLEAR_INSTANT_APP, mPackageName);
+ PackageManager pm = mContext.getPackageManager();
+ pm.clearApplicationUserData(mPackageName, null);
+ });
+ }
+
+ public InstantAppButtonsController show() {
+ bindButtons();
+ mView.setVisibility(View.VISIBLE);
+ return this;
+ }
+}
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 03b3d39..d1bb9d6 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -103,7 +103,6 @@
import com.android.settings.notification.NotificationStation;
import com.android.settings.notification.SoundSettings;
import com.android.settings.notification.ZenAccessSettings;
-import com.android.settings.notification.ZenModeAutomationSettings;
import com.android.settings.notification.ZenModeEventRuleSettings;
import com.android.settings.notification.ZenModePrioritySettings;
import com.android.settings.notification.ZenModeScheduleRuleSettings;
@@ -207,7 +206,6 @@
ApnEditor.class.getName(),
WifiCallingSettings.class.getName(),
ZenModePrioritySettings.class.getName(),
- ZenModeAutomationSettings.class.getName(),
ZenModeScheduleRuleSettings.class.getName(),
ZenModeEventRuleSettings.class.getName(),
ZenModeVisualInterruptionSettings.class.getName(),
diff --git a/src/com/android/settings/development/DevelopmentSettings.java b/src/com/android/settings/development/DevelopmentSettings.java
index da6e800..041019b 100644
--- a/src/com/android/settings/development/DevelopmentSettings.java
+++ b/src/com/android/settings/development/DevelopmentSettings.java
@@ -230,8 +230,6 @@
private static final String KEY_CONVERT_FBE = "convert_to_file_encryption";
private static final String OTA_DISABLE_AUTOMATIC_UPDATE_KEY = "ota_disable_automatic_update";
- private static final String ENABLE_HAL_BINDERIZATION_KEY = "enable_hal_binderization";
- private static final String ENABLE_HAL_BINDERIZATION_PROPERTY = "persist.hal.binderization";
private static final int RESULT_DEBUG_APP = 1000;
private static final int RESULT_MOCK_LOCATION_APP = 1001;
@@ -291,7 +289,6 @@
private ListPreference mBluetoothSelectA2dpLdacPlaybackQuality;
private SwitchPreference mOtaDisableAutomaticUpdate;
- private SwitchPreference mEnableHalBinderization;
private SwitchPreference mWifiAllowScansWithTraffic;
private SwitchPreference mStrictMode;
private SwitchPreference mPointerLocation;
@@ -550,8 +547,6 @@
mOtaDisableAutomaticUpdate = findAndInitSwitchPref(OTA_DISABLE_AUTOMATIC_UPDATE_KEY);
- mEnableHalBinderization = findAndInitSwitchPref(ENABLE_HAL_BINDERIZATION_KEY);
-
mColorModePreference = (ColorModePreference) findPreference(KEY_COLOR_MODE);
mColorModePreference.updateCurrentAndSupported();
if (mColorModePreference.getColorModeCount() < 2) {
@@ -795,7 +790,6 @@
updateShowAllANRsOptions();
updateVerifyAppsOverUsbOptions();
updateOtaDisableAutomaticUpdateOptions();
- updateEnableHalBinderizationOptions();
updateBugreportOptions();
updateForceRtlOptions();
updateLogdSizeValues();
@@ -1040,17 +1034,6 @@
mOtaDisableAutomaticUpdate.isChecked() ? 0 : 1);
}
- private void updateEnableHalBinderizationOptions() {
- updateSwitchPreference(mEnableHalBinderization,
- SystemProperties.getBoolean(ENABLE_HAL_BINDERIZATION_PROPERTY, false));
- }
-
- private void writeEnableHalBinderizationOptions() {
- SystemProperties.set(ENABLE_HAL_BINDERIZATION_PROPERTY,
- mEnableHalBinderization.isChecked() ? "true" : "false");
- pokeSystemProperties();
- }
-
private boolean enableVerifierSetting() {
final ContentResolver cr = getActivity().getContentResolver();
if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) {
@@ -2481,8 +2464,6 @@
writeVerifyAppsOverUsbOptions();
} else if (preference == mOtaDisableAutomaticUpdate) {
writeOtaDisableAutomaticUpdateOptions();
- } else if (preference == mEnableHalBinderization) {
- writeEnableHalBinderizationOptions();
} else if (preference == mStrictMode) {
writeStrictModeVisualOptions();
} else if (preference == mPointerLocation) {
diff --git a/src/com/android/settings/deviceinfo/StorageProfileFragment.java b/src/com/android/settings/deviceinfo/StorageProfileFragment.java
index 1a24962..c5d1045 100644
--- a/src/com/android/settings/deviceinfo/StorageProfileFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageProfileFragment.java
@@ -73,8 +73,7 @@
mPreferenceController.setVolume(mVolume);
mUserId = args.getInt(USER_ID_EXTRA, UserHandle.myUserId());
- // TODO(b/36224168): Use the user id to appropriately badge the preferences.
- mPreferenceController.setUserId(mUserId);
+ mPreferenceController.setUserId(UserHandle.of(mUserId));
}
@Override
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index e22aa24..5b27592 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -20,6 +20,9 @@
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
@@ -165,8 +168,35 @@
/**
* Sets the user id for which this preference controller is handling.
*/
- public void setUserId(int userId) {
- mUserId = userId;
+ public void setUserId(UserHandle userHandle) {
+ mUserId = userHandle.getIdentifier();
+
+ PackageManager pm = mContext.getPackageManager();
+ badgePreference(pm, userHandle, mPhotoPreference);
+ badgePreference(pm, userHandle, mAudioPreference);
+ badgePreference(pm, userHandle, mGamePreference);
+ badgePreference(pm, userHandle, mAppPreference);
+ badgePreference(pm, userHandle, mSystemPreference);
+ badgePreference(pm, userHandle, mFilePreference);
+ }
+
+ private void badgePreference(PackageManager pm, UserHandle userHandle, Preference preference) {
+ if (preference != null) {
+ Drawable currentIcon = preference.getIcon();
+ // Sigh... Applying the badge to the icon clobbers the tint on the base drawable.
+ // For some reason, re-applying it here means the tint remains.
+ currentIcon = applyTint(mContext, currentIcon);
+ preference.setIcon(pm.getUserBadgedIcon(currentIcon, userHandle));
+ }
+ }
+
+ private static Drawable applyTint(Context context, Drawable icon) {
+ TypedArray array =
+ context.obtainStyledAttributes(new int[]{android.R.attr.colorControlNormal});
+ icon = icon.mutate();
+ icon.setTint(array.getColor(0, 0));
+ array.recycle();
+ return icon;
}
@Override
diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java
deleted file mode 100644
index 495e499..0000000
--- a/src/com/android/settings/notification/ZenModeAutomationSettings.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2015 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.notification;
-
-import android.app.AlertDialog;
-import android.app.AutomaticZenRule;
-import android.app.NotificationManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.service.notification.ConditionProviderService;
-import android.service.notification.ZenModeConfig;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.Preference.OnPreferenceClickListener;
-import android.support.v7.preference.PreferenceScreen;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.view.View;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
-import com.android.settings.utils.ManagedServiceSettings.Config;
-import com.android.settings.utils.ZenServiceListing;
-
-import java.lang.ref.WeakReference;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Map;
-
-public class ZenModeAutomationSettings extends ZenModeSettingsBase {
-
- static final Config CONFIG = getConditionProviderConfig();
-
- private PackageManager mPm;
- private ZenServiceListing mServiceListing;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- addPreferencesFromResource(R.xml.zen_mode_automation_settings);
- mPm = mContext.getPackageManager();
- mServiceListing = new ZenServiceListing(mContext, CONFIG);
- mServiceListing.reloadApprovedServices();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- @Override
- protected void onZenModeChanged() {
- // don't care
- }
-
- @Override
- protected void onZenModeConfigChanged() {
- updateControls();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (isUiRestricted()) {
- return;
- }
- updateControls();
- }
-
- private void showAddRuleDialog() {
- new ZenRuleSelectionDialog(mContext, mServiceListing) {
- @Override
- public void onSystemRuleSelected(ZenRuleInfo ri) {
- showNameRuleDialog(ri);
- }
-
- @Override
- public void onExternalRuleSelected(ZenRuleInfo ri) {
- Intent intent = new Intent().setComponent(ri.configurationActivity);
- startActivity(intent);
- }
- }.show();
- }
-
- private void showNameRuleDialog(final ZenRuleInfo ri) {
- new ZenRuleNameDialog(mContext, null) {
- @Override
- public void onOk(String ruleName) {
- mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE_OK);
- AutomaticZenRule rule = new AutomaticZenRule(ruleName, ri.serviceComponent,
- ri.defaultConditionId, NotificationManager.INTERRUPTION_FILTER_PRIORITY,
- true);
- String savedRuleId = addZenRule(rule);
- if (savedRuleId != null) {
- startActivity(getRuleIntent(ri.settingsAction, null, savedRuleId));
- }
- }
- }.show();
- }
-
- private void showDeleteRuleDialog(final String ruleId, final CharSequence ruleName) {
- new AlertDialog.Builder(mContext)
- .setMessage(getString(R.string.zen_mode_delete_rule_confirmation, ruleName))
- .setNegativeButton(R.string.cancel, null)
- .setPositiveButton(R.string.zen_mode_delete_rule_button,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mMetricsFeatureProvider.action(mContext,
- MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
- removeZenRule(ruleId);
- }
- })
- .show();
- }
-
- private Intent getRuleIntent(String settingsAction, ComponentName configurationActivity,
- String ruleId) {
- Intent intent = new Intent()
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
- .putExtra(ConditionProviderService.EXTRA_RULE_ID, ruleId);
- if (configurationActivity != null) {
- intent.setComponent(configurationActivity);
- } else {
- intent.setAction(settingsAction);
- }
- return intent;
- }
-
- private Map.Entry<String,AutomaticZenRule>[] sortedRules() {
- final Map.Entry<String,AutomaticZenRule>[] rt =
- mRules.toArray(new Map.Entry[mRules.size()]);
- Arrays.sort(rt, RULE_COMPARATOR);
- return rt;
- }
-
- private void updateControls() {
- final PreferenceScreen root = getPreferenceScreen();
- root.removeAll();
- final Map.Entry<String,AutomaticZenRule>[] sortedRules = sortedRules();
- for (Map.Entry<String,AutomaticZenRule> sortedRule : sortedRules) {
- ZenRulePreference pref = new ZenRulePreference(getPrefContext(), sortedRule);
- if (pref.appExists) {
- root.addPreference(pref);
- }
- }
- final Preference p = new Preference(getPrefContext());
- p.setIcon(R.drawable.ic_add);
- p.setTitle(R.string.zen_mode_add_rule);
- p.setPersistent(false);
- p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE);
- showAddRuleDialog();
- return true;
- }
- });
- root.addPreference(p);
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.NOTIFICATION_ZEN_MODE_AUTOMATION;
- }
-
- private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
- CharSequence providerLabel) {
- final String mode = computeZenModeCaption(getResources(), rule.getInterruptionFilter());
- final String ruleState = (rule == null || !rule.isEnabled())
- ? getString(R.string.switch_off_text)
- : getString(R.string.zen_mode_rule_summary_enabled_combination, mode);
-
- return isSystemRule ? ruleState
- : getString(R.string.zen_mode_rule_summary_provider_combination,
- providerLabel, ruleState);
- }
-
- private static Config getConditionProviderConfig() {
- final Config c = new Config();
- c.tag = TAG;
- c.setting = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
- c.secondarySetting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
- c.intentAction = ConditionProviderService.SERVICE_INTERFACE;
- c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
- c.noun = "condition provider";
- return c;
- }
-
- private static String computeZenModeCaption(Resources res, int zenMode) {
- switch (zenMode) {
- case NotificationManager.INTERRUPTION_FILTER_ALARMS:
- return res.getString(R.string.zen_mode_option_alarms);
- case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
- return res.getString(R.string.zen_mode_option_important_interruptions);
- case NotificationManager.INTERRUPTION_FILTER_NONE:
- return res.getString(R.string.zen_mode_option_no_interruptions);
- default:
- return null;
- }
- }
-
- public static ZenRuleInfo getRuleInfo(PackageManager pm, ServiceInfo si) {
- if (si == null || si.metaData == null) return null;
- final String ruleType = si.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE);
- final ComponentName configurationActivity = getSettingsActivity(si);
- if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) {
- final ZenRuleInfo ri = new ZenRuleInfo();
- ri.serviceComponent = new ComponentName(si.packageName, si.name);
- ri.settingsAction = Settings.ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS;
- ri.title = ruleType;
- ri.packageName = si.packageName;
- ri.configurationActivity = getSettingsActivity(si);
- ri.packageLabel = si.applicationInfo.loadLabel(pm);
- ri.ruleInstanceLimit =
- si.metaData.getInt(ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
- return ri;
- }
- return null;
- }
-
- private static ComponentName getSettingsActivity(ServiceInfo si) {
- if (si == null || si.metaData == null) return null;
- final String configurationActivity =
- si.metaData.getString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY);
- if (configurationActivity != null) {
- return ComponentName.unflattenFromString(configurationActivity);
- }
- return null;
- }
-
- private static final Comparator<Map.Entry<String,AutomaticZenRule>> RULE_COMPARATOR =
- new Comparator<Map.Entry<String,AutomaticZenRule>>() {
- @Override
- public int compare(Map.Entry<String,AutomaticZenRule> lhs,
- Map.Entry<String,AutomaticZenRule> rhs) {
- int byDate = Long.compare(lhs.getValue().getCreationTime(),
- rhs.getValue().getCreationTime());
- if (byDate != 0) {
- return byDate;
- } else {
- return key(lhs.getValue()).compareTo(key(rhs.getValue()));
- }
- }
-
- private String key(AutomaticZenRule rule) {
- final int type = ZenModeConfig.isValidScheduleConditionId(rule.getConditionId()) ? 1
- : ZenModeConfig.isValidEventConditionId(rule.getConditionId()) ? 2
- : 3;
- return type + rule.getName().toString();
- }
- };
-
- private class ZenRulePreference extends Preference {
- final CharSequence mName;
- final String mId;
- final boolean appExists;
-
- public ZenRulePreference(Context context,
- final Map.Entry<String, AutomaticZenRule> ruleEntry) {
- super(context);
-
- final AutomaticZenRule rule = ruleEntry.getValue();
- mName = rule.getName();
- mId = ruleEntry.getKey();
-
- final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(
- rule.getConditionId());
- final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.getConditionId());
- final boolean isSystemRule = isSchedule || isEvent;
-
- try {
- ApplicationInfo info = mPm.getApplicationInfo(rule.getOwner().getPackageName(), 0);
- LoadIconTask task = new LoadIconTask(this);
- task.execute(info);
- setSummary(computeRuleSummary(rule, isSystemRule, info.loadLabel(mPm)));
- } catch (PackageManager.NameNotFoundException e) {
- setIcon(R.drawable.ic_label);
- appExists = false;
- return;
- }
-
- appExists = true;
- setTitle(rule.getName());
- setPersistent(false);
-
- final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
- : isEvent ? ZenModeEventRuleSettings.ACTION : "";
- ServiceInfo si = mServiceListing.findService(rule.getOwner());
- ComponentName settingsActivity = getSettingsActivity(si);
- setIntent(getRuleIntent(action, settingsActivity, mId));
- setSelectable(settingsActivity != null || isSystemRule);
-
- setWidgetLayoutResource(R.layout.zen_rule_widget);
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder view) {
- super.onBindViewHolder(view);
-
- View v = view.findViewById(R.id.delete_zen_rule);
- if (v != null) {
- v.setOnClickListener(mDeleteListener);
- }
- view.setDividerAllowedAbove(true);
- view.setDividerAllowedBelow(true);
- }
-
- private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showDeleteRuleDialog(mId, mName);
- }
- };
- }
-
- private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> {
- private final WeakReference<Preference> prefReference;
-
- public LoadIconTask(Preference pref) {
- prefReference = new WeakReference<>(pref);
- }
-
- @Override
- protected Drawable doInBackground(ApplicationInfo... params) {
- return params[0].loadIcon(mPm);
- }
-
- @Override
- protected void onPostExecute(Drawable icon) {
- if (icon != null) {
- final Preference pref = prefReference.get();
- if (pref != null) {
- pref.setIcon(icon);
- }
- }
- }
- }
-
-}
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index 695049f..bbcaa9c 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -16,29 +16,56 @@
package com.android.settings.notification;
+import android.app.AlertDialog;
import android.app.AutomaticZenRule;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.provider.Settings;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.ZenModeConfig;
+import com.android.settings.utils.ManagedServiceSettings;
+import com.android.settings.utils.ZenServiceListing;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.view.View;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
public class ZenModeSettings extends ZenModeSettingsBase {
private static final String KEY_PRIORITY_SETTINGS = "priority_settings";
private static final String KEY_VISUAL_SETTINGS = "visual_interruptions_settings";
+ private static final String KEY_AUTOMATIC_RULES = "automatic_rules";
+ static final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
+
+ private PreferenceCategory mAutomaticRules;
private Preference mPrioritySettings;
private Preference mVisualSettings;
private Policy mPolicy;
private SummaryBuilder mSummaryBuilder;
+ private PackageManager mPm;
+ private ZenServiceListing mServiceListing;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -47,10 +74,14 @@
addPreferencesFromResource(R.xml.zen_mode_settings);
final PreferenceScreen root = getPreferenceScreen();
+ mAutomaticRules = (PreferenceCategory) root.findPreference(KEY_AUTOMATIC_RULES);
mPrioritySettings = root.findPreference(KEY_PRIORITY_SETTINGS);
mVisualSettings = root.findPreference(KEY_VISUAL_SETTINGS);
mPolicy = NotificationManager.from(mContext).getNotificationPolicy();
mSummaryBuilder = new SummaryBuilder(getContext());
+ mPm = mContext.getPackageManager();
+ mServiceListing = new ZenServiceListing(mContext, CONFIG);
+ mServiceListing.reloadApprovedServices();
}
@Override
@@ -59,6 +90,7 @@
if (isUiRestricted()) {
return;
}
+ updateControls();
}
@Override
@@ -80,6 +112,7 @@
private void updateControls() {
updatePrioritySettingsSummary();
updateVisualSettingsSummary();
+ updateAutomaticRules();
}
private void updatePrioritySettingsSummary() {
@@ -90,11 +123,251 @@
mVisualSettings.setSummary(mSummaryBuilder.getVisualSettingSummary(mPolicy));
}
+ private void updateAutomaticRules() {
+ mAutomaticRules.removeAll();
+ final Map.Entry<String,AutomaticZenRule>[] sortedRules = sortedRules();
+ for (Map.Entry<String,AutomaticZenRule> sortedRule : sortedRules) {
+ ZenRulePreference pref = new ZenRulePreference(getPrefContext(), sortedRule);
+ if (pref.appExists) {
+ mAutomaticRules.addPreference(pref);
+ }
+ }
+ final Preference p = new Preference(getPrefContext());
+ p.setIcon(R.drawable.ic_add);
+ p.setTitle(R.string.zen_mode_add_rule);
+ p.setPersistent(false);
+ p.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE);
+ showAddRuleDialog();
+ return true;
+ }
+ });
+ mAutomaticRules.addPreference(p);
+ }
+
+ private void showAddRuleDialog() {
+ new ZenRuleSelectionDialog(mContext, mServiceListing) {
+ @Override
+ public void onSystemRuleSelected(ZenRuleInfo ri) {
+ showNameRuleDialog(ri);
+ }
+
+ @Override
+ public void onExternalRuleSelected(ZenRuleInfo ri) {
+ Intent intent = new Intent().setComponent(ri.configurationActivity);
+ startActivity(intent);
+ }
+ }.show();
+ }
+
+ private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
+ CharSequence providerLabel) {
+ final String mode = computeZenModeCaption(getResources(), rule.getInterruptionFilter());
+ final String ruleState = (rule == null || !rule.isEnabled())
+ ? getString(R.string.switch_off_text)
+ : getString(R.string.zen_mode_rule_summary_enabled_combination, mode);
+
+ return isSystemRule ? ruleState
+ : getString(R.string.zen_mode_rule_summary_provider_combination,
+ providerLabel, ruleState);
+ }
+
+ private static ManagedServiceSettings.Config getConditionProviderConfig() {
+ final ManagedServiceSettings.Config c = new ManagedServiceSettings.Config();
+ c.tag = TAG;
+ c.setting = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
+ c.secondarySetting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
+ c.intentAction = ConditionProviderService.SERVICE_INTERFACE;
+ c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
+ c.noun = "condition provider";
+ return c;
+ }
+
+ private static String computeZenModeCaption(Resources res, int zenMode) {
+ switch (zenMode) {
+ case NotificationManager.INTERRUPTION_FILTER_ALARMS:
+ return res.getString(R.string.zen_mode_option_alarms);
+ case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
+ return res.getString(R.string.zen_mode_option_important_interruptions);
+ case NotificationManager.INTERRUPTION_FILTER_NONE:
+ return res.getString(R.string.zen_mode_option_no_interruptions);
+ default:
+ return null;
+ }
+ }
+
+ public static ZenRuleInfo getRuleInfo(PackageManager pm, ServiceInfo si) {
+ if (si == null || si.metaData == null) return null;
+ final String ruleType = si.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE);
+ final ComponentName configurationActivity = getSettingsActivity(si);
+ if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) {
+ final ZenRuleInfo ri = new ZenRuleInfo();
+ ri.serviceComponent = new ComponentName(si.packageName, si.name);
+ ri.settingsAction = Settings.ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS;
+ ri.title = ruleType;
+ ri.packageName = si.packageName;
+ ri.configurationActivity = getSettingsActivity(si);
+ ri.packageLabel = si.applicationInfo.loadLabel(pm);
+ ri.ruleInstanceLimit =
+ si.metaData.getInt(ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
+ return ri;
+ }
+ return null;
+ }
+
+ private static ComponentName getSettingsActivity(ServiceInfo si) {
+ if (si == null || si.metaData == null) return null;
+ final String configurationActivity =
+ si.metaData.getString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY);
+ if (configurationActivity != null) {
+ return ComponentName.unflattenFromString(configurationActivity);
+ }
+ return null;
+ }
+
+ private void showNameRuleDialog(final ZenRuleInfo ri) {
+ new ZenRuleNameDialog(mContext, null) {
+ @Override
+ public void onOk(String ruleName) {
+ mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE_OK);
+ AutomaticZenRule rule = new AutomaticZenRule(ruleName, ri.serviceComponent,
+ ri.defaultConditionId, NotificationManager.INTERRUPTION_FILTER_PRIORITY,
+ true);
+ String savedRuleId = addZenRule(rule);
+ if (savedRuleId != null) {
+ startActivity(getRuleIntent(ri.settingsAction, null, savedRuleId));
+ }
+ }
+ }.show();
+ }
+
+ private void showDeleteRuleDialog(final String ruleId, final CharSequence ruleName) {
+ new AlertDialog.Builder(mContext)
+ .setMessage(getString(R.string.zen_mode_delete_rule_confirmation, ruleName))
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.zen_mode_delete_rule_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mMetricsFeatureProvider.action(mContext,
+ MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
+ removeZenRule(ruleId);
+ }
+ })
+ .show();
+ }
+
+ private Intent getRuleIntent(String settingsAction, ComponentName configurationActivity,
+ String ruleId) {
+ Intent intent = new Intent()
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .putExtra(ConditionProviderService.EXTRA_RULE_ID, ruleId);
+ if (configurationActivity != null) {
+ intent.setComponent(configurationActivity);
+ } else {
+ intent.setAction(settingsAction);
+ }
+ return intent;
+ }
+
+ private Map.Entry<String,AutomaticZenRule>[] sortedRules() {
+ final Map.Entry<String,AutomaticZenRule>[] rt =
+ mRules.toArray(new Map.Entry[mRules.size()]);
+ Arrays.sort(rt, RULE_COMPARATOR);
+ return rt;
+ }
+
@Override
protected int getHelpResource() {
return R.string.help_uri_interruptions;
}
+ private class ZenRulePreference extends Preference {
+ final CharSequence mName;
+ final String mId;
+ final boolean appExists;
+
+ public ZenRulePreference(Context context,
+ final Map.Entry<String, AutomaticZenRule> ruleEntry) {
+ super(context);
+
+ final AutomaticZenRule rule = ruleEntry.getValue();
+ mName = rule.getName();
+ mId = ruleEntry.getKey();
+
+ final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(
+ rule.getConditionId());
+ final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.getConditionId());
+ final boolean isSystemRule = isSchedule || isEvent;
+
+ try {
+ ApplicationInfo info = mPm.getApplicationInfo(rule.getOwner().getPackageName(), 0);
+ LoadIconTask task = new LoadIconTask(this);
+ task.execute(info);
+ setSummary(computeRuleSummary(rule, isSystemRule, info.loadLabel(mPm)));
+ } catch (PackageManager.NameNotFoundException e) {
+ setIcon(R.drawable.ic_label);
+ appExists = false;
+ return;
+ }
+
+ appExists = true;
+ setTitle(rule.getName());
+ setPersistent(false);
+
+ final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
+ : isEvent ? ZenModeEventRuleSettings.ACTION : "";
+ ServiceInfo si = mServiceListing.findService(rule.getOwner());
+ ComponentName settingsActivity = getSettingsActivity(si);
+ setIntent(getRuleIntent(action, settingsActivity, mId));
+ setSelectable(settingsActivity != null || isSystemRule);
+
+ setWidgetLayoutResource(R.layout.zen_rule_widget);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder view) {
+ super.onBindViewHolder(view);
+
+ View v = view.findViewById(R.id.delete_zen_rule);
+ if (v != null) {
+ v.setOnClickListener(mDeleteListener);
+ }
+ }
+
+ private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showDeleteRuleDialog(mId, mName);
+ }
+ };
+ }
+
+ private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> {
+ private final WeakReference<Preference> prefReference;
+
+ public LoadIconTask(Preference pref) {
+ prefReference = new WeakReference<>(pref);
+ }
+
+ @Override
+ protected Drawable doInBackground(ApplicationInfo... params) {
+ return params[0].loadIcon(mPm);
+ }
+
+ @Override
+ protected void onPostExecute(Drawable icon) {
+ if (icon != null) {
+ final Preference pref = prefReference.get();
+ if (pref != null) {
+ pref.setIcon(icon);
+ }
+ }
+ }
+ }
+
public static class SummaryBuilder {
private Context mContext;
@@ -180,6 +453,29 @@
private boolean isEffectSuppressed(Policy policy, int effect) {
return (policy.suppressedVisualEffects & effect) != 0;
}
-
}
+
+ private static final Comparator<Map.Entry<String,AutomaticZenRule>> RULE_COMPARATOR =
+ new Comparator<Map.Entry<String,AutomaticZenRule>>() {
+ @Override
+ public int compare(Map.Entry<String,AutomaticZenRule> lhs,
+ Map.Entry<String,AutomaticZenRule> rhs) {
+ int byDate = Long.compare(lhs.getValue().getCreationTime(),
+ rhs.getValue().getCreationTime());
+ if (byDate != 0) {
+ return byDate;
+ } else {
+ return key(lhs.getValue()).compareTo(key(rhs.getValue()));
+ }
+ }
+
+ private String key(AutomaticZenRule rule) {
+ final int type = ZenModeConfig.isValidScheduleConditionId(rule.getConditionId())
+ ? 1
+ : ZenModeConfig.isValidEventConditionId(rule.getConditionId())
+ ? 2
+ : 3;
+ return type + rule.getName().toString();
+ }
+ };
}
diff --git a/src/com/android/settings/notification/ZenRuleSelectionDialog.java b/src/com/android/settings/notification/ZenRuleSelectionDialog.java
index 9de9a60..4fa632a 100644
--- a/src/com/android/settings/notification/ZenRuleSelectionDialog.java
+++ b/src/com/android/settings/notification/ZenRuleSelectionDialog.java
@@ -169,7 +169,7 @@
if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size());
Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR);
for (ServiceInfo serviceInfo : services) {
- final ZenRuleInfo ri = ZenModeAutomationSettings.getRuleInfo(mPm, serviceInfo);
+ final ZenRuleInfo ri = ZenModeSettings.getRuleInfo(mPm, serviceInfo);
if (ri != null && ri.configurationActivity != null
&& mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName)
&& (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 1ed25f2..d0e21e926 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -149,7 +149,6 @@
@Override
public void onResume() {
mWifiInfo = mWifiManager.getConnectionInfo();
- mWifiConfig = mWifiManager.getWifiApConfiguration();
refreshFromWifiInfo();
setIpText();
@@ -257,4 +256,17 @@
}
mDnsPref.setDetailText(builder.toString());
}
+
+ /**
+ * Forgets the wifi network associated with this preference.
+ */
+ public void forgetNetwork() {
+ if (mWifiConfig.ephemeral) {
+ mWifiManager.disableEphemeralNetwork(mWifiConfig.SSID);
+ } else if (mWifiConfig.isPasspoint()) {
+ mWifiManager.removePasspointConfiguration(mWifiConfig.FQDN);
+ } else {
+ mWifiManager.forget(mWifiConfig.networkId, null /* action listener */);
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index 0073202..ade9d6a 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -19,6 +19,7 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.view.View;
import android.widget.Button;
import com.android.internal.logging.nano.MetricsProto;
@@ -69,17 +70,9 @@
}
private void forgetNetwork() {
- WifiInfo info = mWifiDetailPreferenceController.getWifiInfo();
mMetricsFeatureProvider.action(getActivity(), MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
- if (!info.isEphemeral()) {
- // Network is active but has no network ID - must be ephemeral.
- mWifiManager.disableEphemeralNetwork(
- AccessPoint.convertToQuotedString(info.getSSID()));
- } else if (mAccessPoint.getConfig().isPasspoint()) {
- mWifiManager.removePasspointConfiguration(mAccessPoint.getConfig().FQDN);
- } else {
- mWifiManager.forget(info.getNetworkId(), null /* action listener */);
- }
+ mWifiDetailPreferenceController.forgetNetwork();
+ mForgetButton.setEnabled(false);
}
@Override
diff --git a/tests/app/src/com/android/settings/notification/ZenModeSettingsIntegrationTest.java b/tests/app/src/com/android/settings/notification/ZenModeSettingsIntegrationTest.java
new file mode 100644
index 0000000..e7e5e19
--- /dev/null
+++ b/tests/app/src/com/android/settings/notification/ZenModeSettingsIntegrationTest.java
@@ -0,0 +1,53 @@
+package com.android.settings.notification;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ZenModeSettingsIntegrationTest {
+ private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
+
+ private Context mContext;
+ private UiDevice mUiDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mUiDevice.wakeUp();
+ mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
+ }
+
+ @Test
+ public void testAutomaticRulesAppear() {
+ launchZenSettings();
+ onView(withText("Automatic rules")).check(matches(isDisplayed()));
+ onView(withText("Weekend")).check(matches(isDisplayed()));
+ onView(withText("Add more")).check(matches(isDisplayed())).perform(click());
+ onView(withText("Choose rule type")).check(matches(isDisplayed()));
+ }
+
+ private void launchZenSettings() {
+ Intent settingsIntent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS)
+ .setPackage(mContext.getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(settingsIntent);
+ }
+}
diff --git a/tests/robotests/src/android/net/NetworkScorerAppData.java b/tests/robotests/src/android/net/NetworkScorerAppData.java
index 1eaa8a7..f7da4d1 100644
--- a/tests/robotests/src/android/net/NetworkScorerAppData.java
+++ b/tests/robotests/src/android/net/NetworkScorerAppData.java
@@ -23,13 +23,20 @@
* wifi networks automatically" feature.
*/
private final ComponentName mEnableUseOpenWifiActivity;
+ /**
+ * The {@link android.app.NotificationChannel} ID used by {@link #mRecommendationService} to
+ * post open network notifications.
+ */
+ private final String mNetworkAvailableNotificationChannelId;
public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
- String recommendationServiceLabel, ComponentName enableUseOpenWifiActivity) {
+ String recommendationServiceLabel, ComponentName enableUseOpenWifiActivity,
+ String networkAvailableNotificationChannelId) {
this.packageUid = packageUid;
this.mRecommendationService = recommendationServiceComp;
this.mRecommendationServiceLabel = recommendationServiceLabel;
this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
+ this.mNetworkAvailableNotificationChannelId = networkAvailableNotificationChannelId;
}
protected NetworkScorerAppData(Parcel in) {
@@ -37,6 +44,7 @@
mRecommendationService = ComponentName.readFromParcel(in);
mRecommendationServiceLabel = in.readString();
mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
+ mNetworkAvailableNotificationChannelId = in.readString();
}
@Override
@@ -45,6 +53,7 @@
ComponentName.writeToParcel(mRecommendationService, dest);
dest.writeString(mRecommendationServiceLabel);
ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
+ dest.writeString(mNetworkAvailableNotificationChannelId);
}
@Override
@@ -83,6 +92,11 @@
return mRecommendationServiceLabel;
}
+ @Nullable
+ public String getNetworkAvailableNotificationChannelId() {
+ return mNetworkAvailableNotificationChannelId;
+ }
+
@Override
public String toString() {
return "NetworkScorerAppData{" +
@@ -90,6 +104,8 @@
", mRecommendationService=" + mRecommendationService +
", mRecommendationServiceLabel=" + mRecommendationServiceLabel +
", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
+ ", mNetworkAvailableNotificationChannelId=" +
+ mNetworkAvailableNotificationChannelId +
'}';
}
@@ -101,12 +117,14 @@
return packageUid == that.packageUid &&
Objects.equals(mRecommendationService, that.mRecommendationService) &&
Objects.equals(mRecommendationServiceLabel, that.mRecommendationServiceLabel) &&
- Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
+ Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity) &&
+ Objects.equals(mNetworkAvailableNotificationChannelId,
+ that.mNetworkAvailableNotificationChannelId);
}
@Override
public int hashCode() {
return Objects.hash(packageUid, mRecommendationService, mRecommendationServiceLabel,
- mEnableUseOpenWifiActivity);
+ mEnableUseOpenWifiActivity, mNetworkAvailableNotificationChannelId);
}
}
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java
index bf00889..209cdeb 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java
@@ -23,11 +23,18 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.UserManager;
+import android.support.v7.preference.Preference;
+import android.view.View;
+import android.widget.Button;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.applications.instantapps.InstantAppButtonsController;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
import org.junit.Before;
@@ -41,6 +48,7 @@
import org.robolectric.util.ReflectionHelpers;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -51,6 +59,11 @@
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class InstalledAppDetailsTest {
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+
+ @Mock
+ ApplicationFeatureProvider mApplicationFeatureProvider;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private UserManager mUserManager;
@@ -65,6 +78,10 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mAppDetail = new InstalledAppDetails();
+
+ // Default to not considering any apps to be instant (individual tests can override this).
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> false));
}
@Test
@@ -136,4 +153,119 @@
assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isTrue();
verify(mActivity, never()).finishAndRemoveTask();
}
+
+ // Tests that we don't show the "uninstall for all users" button for instant apps.
+ @Test
+ public void instantApps_noUninstallForAllButton() {
+ // Make this app appear to be instant.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+ when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
+ when(mUserManager.getUsers().size()).thenReturn(2);
+
+ final ApplicationInfo info = new ApplicationInfo();
+ info.enabled = true;
+ final AppEntry appEntry = mock(AppEntry.class);
+ appEntry.info = info;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+
+ ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
+ ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
+ ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
+
+ assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
+ }
+
+ // Tests that we don't show the uninstall button for instant apps"
+ @Test
+ public void instantApps_noUninstallButton() {
+ // Make this app appear to be instant.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+ final ApplicationInfo info = new ApplicationInfo();
+ info.flags = ApplicationInfo.FLAG_INSTALLED;
+ info.enabled = true;
+ final AppEntry appEntry = mock(AppEntry.class);
+ appEntry.info = info;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = info;
+ final Button uninstallButton = mock(Button.class);
+
+ ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
+ ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
+ ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
+ ReflectionHelpers.setField(mAppDetail, "mUninstallButton", uninstallButton);
+
+ mAppDetail.initUnintsallButtonForUserApp();
+ verify(uninstallButton).setVisibility(View.GONE);
+ }
+
+ // Tests that we don't show the force stop button for instant apps (they aren't allowed to run
+ // when they aren't in the foreground).
+ @Test
+ public void instantApps_noForceStop() {
+ // Make this app appear to be instant.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ final AppEntry appEntry = mock(AppEntry.class);
+ final ApplicationInfo info = new ApplicationInfo();
+ appEntry.info = info;
+ final Button forceStopButton = mock(Button.class);
+
+ ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
+ ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
+ ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
+ ReflectionHelpers.setField(mAppDetail, "mForceStopButton", forceStopButton);
+
+ mAppDetail.checkForceStop();
+ verify(forceStopButton).setVisibility(View.GONE);
+ }
+
+ // A helper class for testing the InstantAppButtonsController - it lets us look up the
+ // preference associated with a key for instant app buttons and get back a mock
+ // LayoutPreference (to avoid a null pointer exception).
+ public static class InstalledAppDetailsWithMockInstantButtons extends InstalledAppDetails {
+ @Mock
+ private LayoutPreference mInstantButtons;
+
+ public InstalledAppDetailsWithMockInstantButtons() {
+ super();
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Override
+ public Preference findPreference(CharSequence key) {
+ if (key == "instant_app_buttons") {
+ return mInstantButtons;
+ }
+ return super.findPreference(key);
+ }
+ }
+
+ @Test
+ public void instantApps_instantSpecificButtons() {
+ // Make this app appear to be instant.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+
+ final InstalledAppDetailsWithMockInstantButtons
+ fragment = new InstalledAppDetailsWithMockInstantButtons();
+ ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
+
+ final InstantAppButtonsController buttonsController =
+ mock(InstantAppButtonsController.class);
+ when(buttonsController.setPackageName(anyString())).thenReturn(buttonsController);
+
+ FakeFeatureFactory.setupForTest(mContext);
+ FakeFeatureFactory factory =
+ (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+ when(factory.applicationFeatureProvider.newInstantAppButtonsController(any(),
+ any())).thenReturn(buttonsController);
+
+ fragment.maybeAddInstantAppButtons();
+ verify(buttonsController).setPackageName(anyString());
+ verify(buttonsController).show();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index 18b0c82..7d1f79b 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -31,6 +31,7 @@
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
import android.support.v7.preference.PreferenceScreen;
@@ -243,4 +244,43 @@
assertThat(system.getSummary().toString()).isEqualTo("16.00KB");
assertThat(files.getSummary().toString()).isEqualTo("5.00KB");
}
+
+ @Test
+ public void settingUserIdAppliesNewIcons() {
+ StorageItemPreference audio = spy(new StorageItemPreference(mContext));
+ audio.setIcon(R.drawable.ic_photo_library_vd_theme_24);
+ StorageItemPreference image = spy(new StorageItemPreference(mContext));
+ image.setIcon(R.drawable.ic_photo_library_vd_theme_24);
+ StorageItemPreference games = spy(new StorageItemPreference(mContext));
+ games.setIcon(R.drawable.ic_photo_library_vd_theme_24);
+ StorageItemPreference apps = spy(new StorageItemPreference(mContext));
+ apps.setIcon(R.drawable.ic_photo_library_vd_theme_24);
+ StorageItemPreference system = spy(new StorageItemPreference(mContext));
+ system.setIcon(R.drawable.ic_photo_library_vd_theme_24);
+ StorageItemPreference files = spy(new StorageItemPreference(mContext));
+ files.setIcon(R.drawable.ic_photo_library_vd_theme_24);
+ PreferenceScreen screen = mock(PreferenceScreen.class);
+ when(screen.findPreference(
+ eq(StorageItemPreferenceController.AUDIO_KEY))).thenReturn(audio);
+ when(screen.findPreference(
+ eq(StorageItemPreferenceController.PHOTO_KEY))).thenReturn(image);
+ when(screen.findPreference(
+ eq(StorageItemPreferenceController.GAME_KEY))).thenReturn(games);
+ when(screen.findPreference(
+ eq(StorageItemPreferenceController.OTHER_APPS_KEY))).thenReturn(apps);
+ when(screen.findPreference(
+ eq(StorageItemPreferenceController.SYSTEM_KEY))).thenReturn(system);
+ when(screen.findPreference(
+ eq(StorageItemPreferenceController.FILES_KEY))).thenReturn(files);
+ mController.displayPreference(screen);
+
+ mController.setUserId(new UserHandle(10));
+
+ verify(audio, times(2)).setIcon(any(Drawable.class));
+ verify(image, times(2)).setIcon(any(Drawable.class));
+ verify(games, times(2)).setIcon(any(Drawable.class));
+ verify(apps, times(2)).setIcon(any(Drawable.class));
+ verify(system, times(2)).setIcon(any(Drawable.class));
+ verify(files, times(2)).setIcon(any(Drawable.class));
+ }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/network/NetworkScorerPickerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/NetworkScorerPickerPreferenceControllerTest.java
index 6bf47ac..1e468a3 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkScorerPickerPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkScorerPickerPreferenceControllerTest.java
@@ -68,7 +68,8 @@
Settings.System.putInt(mContext.getContentResolver(), NETWORK_RECOMMENDATIONS_ENABLED, 1);
ComponentName scorer = new ComponentName(TEST_SCORER_PACKAGE, TEST_SCORER_CLASS);
NetworkScorerAppData scorerAppData = new NetworkScorerAppData(
- 0, scorer, TEST_SCORER_LABEL, null /* enableUseOpenWifiActivity */);
+ 0, scorer, TEST_SCORER_LABEL, null /* enableUseOpenWifiActivity */,
+ null /* networkAvailableNotificationChannelId */);
when(mNetworkScorer.getActiveScorer()).thenReturn(scorerAppData);
Preference preference = mock(Preference.class);
diff --git a/tests/robotests/src/com/android/settings/network/NetworkScorerPickerTest.java b/tests/robotests/src/com/android/settings/network/NetworkScorerPickerTest.java
index fef6f85..bb8635f 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkScorerPickerTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkScorerPickerTest.java
@@ -118,7 +118,8 @@
public void testUpdateCandidates_validScorer() {
ComponentName scorer = new ComponentName(TEST_SCORER_PACKAGE_1, TEST_SCORER_CLASS_1);
NetworkScorerAppData scorerAppData = new NetworkScorerAppData(
- 0, scorer, TEST_SCORER_LABEL_1, null /* enableUseOpenWifiActivity */);
+ 0, scorer, TEST_SCORER_LABEL_1, null /* enableUseOpenWifiActivity */,
+ null /* networkAvailableNotificationChannelId */);
when(mNetworkScoreManager.getAllValidScorers()).thenReturn(
Lists.newArrayList(scorerAppData));
when(mNetworkScoreManager.getActiveScorerPackage()).thenReturn(TEST_SCORER_PACKAGE_1);
diff --git a/tests/robotests/src/com/android/settings/wifi/UseOpenWifiPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/UseOpenWifiPreferenceControllerTest.java
index aa89464..5b55006 100644
--- a/tests/robotests/src/com/android/settings/wifi/UseOpenWifiPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/UseOpenWifiPreferenceControllerTest.java
@@ -56,9 +56,9 @@
public class UseOpenWifiPreferenceControllerTest {
private static ComponentName ENABLE_ACTIVITY_COMPONENT = new ComponentName("package", "activityClass");
private static NetworkScorerAppData APP_DATA =
- new NetworkScorerAppData(0, null, null, ENABLE_ACTIVITY_COMPONENT);
+ new NetworkScorerAppData(0, null, null, ENABLE_ACTIVITY_COMPONENT, null);
private static NetworkScorerAppData APP_DATA_NO_ACTIVITY =
- new NetworkScorerAppData(0, null, null, null);
+ new NetworkScorerAppData(0, null, null, null, null);
@Mock private Lifecycle mLifecycle;
@Mock private Fragment mFragment;
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index a7e12b3..88a63b3 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -84,8 +84,6 @@
MockitoAnnotations.initMocks(this);
mLifecycle = new Lifecycle();
- mController = new WifiDetailPreferenceController(
- mockAccessPoint, mContext, mLifecycle, mockWifiManager);
when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig);
when(mockAccessPoint.getLevel()).thenReturn(LEVEL);
@@ -93,11 +91,13 @@
when(mockAccessPoint.getRssi()).thenReturn(RSSI);
when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY);
+ mController = new WifiDetailPreferenceController(
+ mockAccessPoint, mContext, mLifecycle, mockWifiManager);
+
setupMockedPreferenceScreen();
- when (mockWifiInfo.getRssi()).thenReturn(RSSI);
+ when(mockWifiInfo.getRssi()).thenReturn(RSSI);
when(mockWifiManager.getConnectionInfo()).thenReturn(mockWifiInfo);
- when(mockWifiManager.getWifiApConfiguration()).thenReturn(mockWifiConfig);
}
private void setupMockedPreferenceScreen() {
@@ -139,7 +139,6 @@
mController.onResume();
verify(mockWifiManager).getConnectionInfo();
- verify(mockWifiManager).getWifiApConfiguration();
}
@Test
@@ -178,4 +177,29 @@
verify(mockSignalStrengthPref).setDetailText(expectedStrength);
}
+
+ @Test
+ public void forgetNetwork_ephemeral() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.SSID = "ssid";
+ // WifiConfiguration#isEphemeral will not be visible in robolectric until O is supported
+ wifiConfiguration.ephemeral = true;
+ when(mockAccessPoint.getConfig()).thenReturn(wifiConfiguration);
+
+ mController = new WifiDetailPreferenceController(
+ mockAccessPoint, mContext, mLifecycle, mockWifiManager);
+
+ mController.forgetNetwork();
+
+ verify(mockWifiManager).disableEphemeralNetwork(wifiConfiguration.SSID);
+ }
+
+ @Test
+ public void forgetNetwork_saved() {
+ mockWifiConfig.networkId = 5;
+
+ mController.forgetNetwork();
+
+ verify(mockWifiManager).forget(mockWifiConfig.networkId, null);
+ }
}