Merge "Remove extra IndexProviders that provided bad data."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 22c2c59..0501077 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2296,6 +2296,18 @@
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
+ <activity android:name="Settings$ManagedProfileSettingsActivity"
+ android:label="@string/managed_profile_settings_title"
+ android:taskAffinity=""
+ android:parentActivityName="Settings"
+ android:permission="android.permission.MANAGE_USERS">
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.MANAGED_PROFILE_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.accounts.ManagedProfileSettings" />
+ </activity>
<activity android:name="com.android.settings.accounts.AddAccountSettings"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6bab594..852e81d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1579,6 +1579,8 @@
<string name="wifi_starting">Turning Wi\u2011Fi on\u2026</string>
<!-- Summary text when turning Wi-Fi or bluetooth off -->
<string name="wifi_stopping">Turning off Wi\u2011Fi\u2026</string>
+ <!-- Title of Button to show all Wi-Fi networks in the picker. [CHAR LIMIT=30] -->
+ <string name="wifi_see_all_networks_button_title">See all networks</string>
<!-- Summary text when Wi-Fi or bluetooth has error -->
<string name="wifi_error">Error</string>
<!-- Summary text when wifi SoftAP started failed due to no legal usable channel allowed in this region by regulatory -->
@@ -2939,7 +2941,7 @@
<string name="tether_settings_title_bluetooth">Bluetooth tethering</string>
<!-- Tethering controls, item title to go into the tethering settings when USB and Bluetooth tethering are available [CHAR LIMIT=25]-->
<string name="tether_settings_title_usb_bluetooth">Tethering</string>
- <!-- Tethering controls, item title to go into the tethering settings when USB, Bluetooth and Wifi tethering are available [CHAR LIMIT=25]-->
+ <!-- Tethering controls, item title to go into the tethering settings when USB, Bluetooth and Wifi tethering are available [CHAR LIMIT=50]-->
<string name="tether_settings_title_all">Hotspot & Tethering</string>
<!-- Tethering setting summary when both Wi-Fi hotspot and tether are turned on [CHAR LIMIT=NONE]-->
<string name="tether_settings_summary_hotspot_on_tether_on">Hotspot on, tethering</string>
@@ -5991,7 +5993,9 @@
handle actions such as open web page, making phone calls, default SMS apps [CHAR LIMIT=40]-->
<string name="app_default_dashboard_title">Default apps</string>
<!-- Summary text for system preference tile, showing important setting items under system setting [CHAR LIMIT=NONE]-->
- <string name="system_dashboard_summary">Languages, backup, updates, about phone</string>
+ <string name="system_dashboard_summary" product="default">Languages, backup, updates, about phone</string>
+ <!-- Summary text for system preference tile, showing important setting items under system setting [CHAR LIMIT=NONE]-->
+ <string name="system_dashboard_summary" product="tablet">Languages, backup, updates, about device</string>
<!-- Search strings -->
<!-- Text to describe the search results fragment title [CHAR LIMIT=16] -->
diff --git a/res/xml/account_type_settings.xml b/res/xml/account_type_settings.xml
index 6663d7b..ab997a5 100644
--- a/res/xml/account_type_settings.xml
+++ b/res/xml/account_type_settings.xml
@@ -23,22 +23,22 @@
android:key="account_header"
android:layout="@layout/account_header"
android:selectable="false"
- android:order="0"/>
+ android:order="-10000"/>
<Preference
android:key="account_sync"
android:title="@string/account_sync_title"
android:icon="@drawable/ic_sync"
- android:order="1"/>
+ android:order="-9999"/>
<PreferenceCategory
android:key="dashboard_tile_placeholder"
- android:order="10"/>
+ android:order="-9998"/>
<com.android.settings.applications.LayoutPreference
android:key="remove_account"
android:layout="@layout/remove_account_button"
- android:order="100"
+ android:order="1000"
android:selectable="false"/>
</PreferenceScreen>
diff --git a/res/xml/ia_sound_settings.xml b/res/xml/ia_sound_settings.xml
index e63db0d..27fcdda 100644
--- a/res/xml/ia_sound_settings.xml
+++ b/res/xml/ia_sound_settings.xml
@@ -60,32 +60,34 @@
<PreferenceCategory
android:key="ringtones_preferecence_category"
- android:title="@string/ringtones_category_preference_title" />
+ android:title="@string/ringtones_category_preference_title" >
- <!-- Phone ringtone -->
- <com.android.settings.DefaultRingtonePreference
- android:key="ringtone"
- android:title="@string/ringtone_title"
- android:dialogTitle="@string/ringtone_title"
- android:summary="@string/ringtone_summary"
- android:ringtoneType="ringtone" />
+ <!-- Phone ringtone -->
+ <com.android.settings.DefaultRingtonePreference
+ android:key="ringtone"
+ android:title="@string/ringtone_title"
+ android:dialogTitle="@string/ringtone_title"
+ android:summary="@string/ringtone_summary"
+ android:ringtoneType="ringtone" />
- <!-- Default notification ringtone -->
- <com.android.settings.DefaultRingtonePreference
- android:key="notification_ringtone"
- android:title="@string/notification_ringtone_title"
- android:dialogTitle="@string/notification_ringtone_title"
- android:summary="@string/ringtone_summary"
- android:ringtoneType="notification" />
+ <!-- Default notification ringtone -->
+ <com.android.settings.DefaultRingtonePreference
+ android:key="notification_ringtone"
+ android:title="@string/notification_ringtone_title"
+ android:dialogTitle="@string/notification_ringtone_title"
+ android:summary="@string/ringtone_summary"
+ android:ringtoneType="notification" />
- <!-- Default alarm ringtone -->
- <com.android.settings.DefaultRingtonePreference
- android:key="alarm_ringtone"
- android:title="@string/alarm_ringtone_title"
- android:dialogTitle="@string/alarm_ringtone_title"
- android:summary="@string/ringtone_summary"
- android:persistent="false"
- android:ringtoneType="alarm" />
+ <!-- Default alarm ringtone -->
+ <com.android.settings.DefaultRingtonePreference
+ android:key="alarm_ringtone"
+ android:title="@string/alarm_ringtone_title"
+ android:dialogTitle="@string/alarm_ringtone_title"
+ android:summary="@string/ringtone_summary"
+ android:persistent="false"
+ android:ringtoneType="alarm" />
+
+ </PreferenceCategory>
<!-- Other sounds -->
<PreferenceCategory
diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml
index f6d6310..e08ca96 100644
--- a/res/xml/storage_dashboard_fragment.xml
+++ b/res/xml/storage_dashboard_fragment.xml
@@ -43,4 +43,10 @@
android:key="pref_system"
android:title="@string/storage_detail_system">
</com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
+ <Preference
+ android:key="manage_storage"
+ android:title="@string/storage_menu_manage"
+ android:icon="@drawable/ic_settings_storage"
+ android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings">
+ </Preference>
</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
index a5f9830..40972ac 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
@@ -366,13 +366,22 @@
}
}
+ /**
+ * Dialog setup.
+ * <p>
+ * To make it less likely that the dialog is dismissed accidentally, for example if the
+ * device is malfunctioning or if the device is in a pocket, we set
+ * {@code setCanceledOnTouchOutside(false)}.
+ */
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- return new AlertDialog.Builder(getActivity())
+ Dialog dialog = new AlertDialog.Builder(getActivity())
.setTitle(getArguments().getString(ARG_TITLE))
.setMessage(getArguments().getInt(ARG_MESSAGE))
.setPositiveButton(getArguments().getInt(ARG_BUTTON), null)
.create();
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
}
@Override
diff --git a/src/com/android/settings/CreateShortcut.java b/src/com/android/settings/CreateShortcut.java
index 726bf0a..56ab34a 100644
--- a/src/com/android/settings/CreateShortcut.java
+++ b/src/com/android/settings/CreateShortcut.java
@@ -39,7 +39,9 @@
import android.widget.ImageView;
import android.widget.ListView;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.Settings.TetherSettingsActivity;
+import com.android.settings.overlay.FeatureFactory;
import java.util.ArrayList;
import java.util.List;
@@ -56,7 +58,8 @@
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
- ListItem item = itemForPosition(position);
+ final ListItem item = itemForPosition(position);
+ logCreateShortcut(item.resolveInfo);
setResult(RESULT_OK, createResultIntent(intentForPosition(position),
item.resolveInfo, item.label));
finish();
@@ -89,6 +92,15 @@
return intent;
}
+ private void logCreateShortcut(ResolveInfo info) {
+ if (info == null || info.activityInfo == null) {
+ return;
+ }
+ FeatureFactory.getFactory(this).getMetricsFeatureProvider().action(
+ this, MetricsProto.MetricsEvent.ACTION_SETTINGS_CREATE_SHORTCUT,
+ info.activityInfo.name);
+ }
+
private Bitmap createIcon(int resource) {
Context context = new ContextThemeWrapper(this, android.R.style.Theme_Material);
View view = LayoutInflater.from(context).inflate(R.layout.shortcut_badge, null);
@@ -165,7 +177,7 @@
continue;
}
updates.add(new ShortcutInfo.Builder(mContext, info.getId())
- .setShortLabel(ri.loadLabel(pm)).build());
+ .setShortLabel(ri.loadLabel(pm)).build());
}
if (!updates.isEmpty()) {
sm.updateShortcuts(updates);
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index f274114..b66f2f5 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -1300,8 +1300,13 @@
dashboardFeatureProvider.getTilesForCategory(CategoryKey.CATEGORY_SECURITY);
mSummaryLoader.setSummary(this, getPackageVerifierSummary(dashboardCategory));
} else {
- mSummaryLoader.setSummary(this,
- mContext.getString(R.string.security_dashboard_summary));
+ final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(mContext);
+ if (fpm != null && fpm.isHardwareDetected()) {
+ mSummaryLoader.setSummary(this,
+ mContext.getString(R.string.security_dashboard_summary));
+ } else {
+ mSummaryLoader.setSummary(this, null);
+ }
}
}
@@ -1319,8 +1324,7 @@
String summaryUri = tile.metaData.getString(
TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, null);
return TileUtils.getTextFromUri(mContext, summaryUri,
- new ArrayMap<String, IContentProvider>(),
- TileUtils.META_DATA_PREFERENCE_SUMMARY);
+ new ArrayMap<>(), TileUtils.META_DATA_PREFERENCE_SUMMARY);
}
return null;
}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 179b31b..9168ead 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -69,7 +69,6 @@
import com.android.settingslib.drawer.SettingsDrawerActivity;
import com.android.settingslib.drawer.Tile;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -528,8 +527,9 @@
}
}
- if (DEBUG_TIMING) Log.d(LOG_TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
- + " ms");
+ if (DEBUG_TIMING) {
+ Log.d(LOG_TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms");
+ }
}
public void setDisplaySearchMenu(boolean displaySearch) {
diff --git a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
index 8143e96..801a20b 100644
--- a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
@@ -24,6 +24,7 @@
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Utils;
@@ -84,7 +85,7 @@
if (mAccountLabel != null) {
getActivity().setTitle(mAccountLabel);
}
- updateAccountHeader();
+ updateUi();
}
@Override
@@ -125,7 +126,7 @@
}
@VisibleForTesting
- void updateAccountHeader() {
+ void updateUi() {
final Preference headerPreference = findPreference(KEY_ACCOUNT_HEADER);
headerPreference.setTitle(mAccount.name);
final Context context = getContext();
@@ -136,6 +137,13 @@
}
final AuthenticatorHelper helper = new AuthenticatorHelper(context, userHandle, null);
headerPreference.setIcon(helper.getDrawableForType(context, mAccountType));
+ final AccountTypePreferenceLoader accountTypePreferenceLoader =
+ new AccountTypePreferenceLoader(this, helper, userHandle);
+ PreferenceScreen prefs =
+ accountTypePreferenceLoader.addPreferencesForType(mAccountType, getPreferenceScreen());
+ if (prefs != null) {
+ accountTypePreferenceLoader.updatePreferenceIntents(prefs, mAccountType, mAccount);
+ }
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/accounts/AccountPreferenceBase.java b/src/com/android/settings/accounts/AccountPreferenceBase.java
index aa5c518..605688e 100644
--- a/src/com/android/settings/accounts/AccountPreferenceBase.java
+++ b/src/com/android/settings/accounts/AccountPreferenceBase.java
@@ -58,6 +58,7 @@
private Object mStatusChangeListenerHandle;
protected AuthenticatorHelper mAuthenticatorHelper;
protected UserHandle mUserHandle;
+ protected AccountTypePreferenceLoader mAccountTypePreferenceLoader;
private java.text.DateFormat mDateFormat;
private java.text.DateFormat mTimeFormat;
@@ -70,6 +71,8 @@
mUserHandle = Utils.getSecureTargetUser(activity.getActivityToken(), mUm, getArguments(),
activity.getIntent().getExtras());
mAuthenticatorHelper = new AuthenticatorHelper(activity, mUserHandle, this);
+ mAccountTypePreferenceLoader =
+ new AccountTypePreferenceLoader(this, mAuthenticatorHelper, mUserHandle);
}
/**
@@ -142,35 +145,7 @@
*/
public PreferenceScreen addPreferencesForType(final String accountType,
PreferenceScreen parent) {
- PreferenceScreen prefs = null;
- if (mAuthenticatorHelper.containsAccountType(accountType)) {
- AuthenticatorDescription desc = null;
- try {
- desc = mAuthenticatorHelper.getAccountTypeDescription(accountType);
- if (desc != null && desc.accountPreferencesId != 0) {
- // Load the context of the target package, then apply the
- // base Settings theme (no references to local resources)
- // and create a context theme wrapper so that we get the
- // correct text colors. Control colors will still be wrong,
- // but there's not much we can do about it since we can't
- // reference local color resources.
- final Context targetCtx = getActivity().createPackageContextAsUser(
- desc.packageName, 0, mUserHandle);
- final Theme baseTheme = getResources().newTheme();
- baseTheme.applyStyle(com.android.settings.R.style.Theme_SettingsBase, true);
- final Context themedCtx =
- new LocalClassLoaderContextThemeWrapper(getClass(), targetCtx, 0);
- themedCtx.getTheme().setTo(baseTheme);
- prefs = getPreferenceManager().inflateFromResource(themedCtx,
- desc.accountPreferencesId, parent);
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Couldn't load preferences.xml file from " + desc.packageName);
- } catch (Resources.NotFoundException e) {
- Log.w(TAG, "Couldn't load preferences.xml file from " + desc.packageName);
- }
- }
- return prefs;
+ return mAccountTypePreferenceLoader.addPreferencesForType(accountType, parent);
}
public void updateAuthDescriptions() {
diff --git a/src/com/android/settings/accounts/AccountTypePreferenceLoader.java b/src/com/android/settings/accounts/AccountTypePreferenceLoader.java
new file mode 100644
index 0000000..87f9c77
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountTypePreferenceLoader.java
@@ -0,0 +1,245 @@
+/*
+
+ * 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.accounts;
+
+import android.accounts.Account;
+import android.accounts.AuthenticatorDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.os.UserHandle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceClickListener;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.location.LocationSettings;
+import com.android.settings.utils.LocalClassLoaderContextThemeWrapper;
+import com.android.settingslib.accounts.AuthenticatorHelper;
+
+/**
+ * Class to load the preference screen to be added to the settings page for the specific account
+ * type as specified in the account-authenticator.
+ */
+public class AccountTypePreferenceLoader {
+
+ private static final String TAG = "AccountTypePrefLoader";
+ private static final String ACCOUNT_KEY = "account"; // to pass to auth settings
+ // Action name for the broadcast intent when the Google account preferences page is launching
+ // the location settings.
+ private static final String LAUNCHING_LOCATION_SETTINGS =
+ "com.android.settings.accounts.LAUNCHING_LOCATION_SETTINGS";
+
+
+ private AuthenticatorHelper mAuthenticatorHelper;
+ private UserHandle mUserHandle;
+ private PreferenceFragment mFragment;
+
+ public AccountTypePreferenceLoader(PreferenceFragment fragment,
+ AuthenticatorHelper authenticatorHelper, UserHandle userHandle) {
+ mFragment = fragment;
+ mAuthenticatorHelper = authenticatorHelper;
+ mUserHandle = userHandle;
+ }
+
+ /**
+ * Gets the preferences.xml file associated with a particular account type.
+ * @param accountType the type of account
+ * @return a PreferenceScreen inflated from accountPreferenceId.
+ */
+ public PreferenceScreen addPreferencesForType(final String accountType,
+ PreferenceScreen parent) {
+ PreferenceScreen prefs = null;
+ if (mAuthenticatorHelper.containsAccountType(accountType)) {
+ AuthenticatorDescription desc = null;
+ try {
+ desc = mAuthenticatorHelper.getAccountTypeDescription(accountType);
+ if (desc != null && desc.accountPreferencesId != 0) {
+ // Load the context of the target package, then apply the
+ // base Settings theme (no references to local resources)
+ // and create a context theme wrapper so that we get the
+ // correct text colors. Control colors will still be wrong,
+ // but there's not much we can do about it since we can't
+ // reference local color resources.
+ final Context targetCtx = mFragment.getActivity().createPackageContextAsUser(
+ desc.packageName, 0, mUserHandle);
+ final Theme baseTheme = mFragment.getResources().newTheme();
+ baseTheme.applyStyle(R.style.Theme_SettingsBase, true);
+ final Context themedCtx =
+ new LocalClassLoaderContextThemeWrapper(getClass(), targetCtx, 0);
+ themedCtx.getTheme().setTo(baseTheme);
+ prefs = mFragment.getPreferenceManager().inflateFromResource(themedCtx,
+ desc.accountPreferencesId, parent);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Couldn't load preferences.xml file from " + desc.packageName);
+ } catch (Resources.NotFoundException e) {
+ Log.w(TAG, "Couldn't load preferences.xml file from " + desc.packageName);
+ }
+ }
+ return prefs;
+ }
+
+ /**
+ * Recursively filters through the preference list provided by GoogleLoginService.
+ *
+ * This method removes all the invalid intent from the list, adds account name as extra into the
+ * intent, and hack the location settings to start it as a fragment.
+ */
+ public void updatePreferenceIntents(PreferenceGroup prefs, final String acccountType,
+ Account account) {
+ final PackageManager pm = mFragment.getActivity().getPackageManager();
+ for (int i = 0; i < prefs.getPreferenceCount(); ) {
+ Preference pref = prefs.getPreference(i);
+ if (pref instanceof PreferenceGroup) {
+ updatePreferenceIntents((PreferenceGroup) pref, acccountType, account);
+ }
+ Intent intent = pref.getIntent();
+ if (intent != null) {
+ // Hack. Launch "Location" as fragment instead of as activity.
+ //
+ // When "Location" is launched as activity via Intent, there's no "Up" button at the
+ // top left, and if there's another running instance of "Location" activity, the
+ // back stack would usually point to some other place so the user won't be able to
+ // go back to the previous page by "back" key. Using fragment is a much easier
+ // solution to those problems.
+ //
+ // If we set Intent to null and assign a fragment to the PreferenceScreen item here,
+ // in order to make it work as expected, we still need to modify the container
+ // PreferenceActivity, override onPreferenceStartFragment() and call
+ // startPreferencePanel() there. In order to inject the title string there, more
+ // dirty further hack is still needed. It's much easier and cleaner to listen to
+ // preference click event here directly.
+ if (intent.getAction().equals(
+ android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)) {
+ // The OnPreferenceClickListener overrides the click event completely. No intent
+ // will get fired.
+ pref.setOnPreferenceClickListener(new FragmentStarter(
+ LocationSettings.class.getName(), R.string.location_settings_title));
+ } else {
+ ResolveInfo ri = pm.resolveActivityAsUser(intent,
+ PackageManager.MATCH_DEFAULT_ONLY, mUserHandle.getIdentifier());
+ if (ri == null) {
+ prefs.removePreference(pref);
+ continue;
+ }
+ intent.putExtra(ACCOUNT_KEY, account);
+ intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+ pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Intent prefIntent = preference.getIntent();
+ /*
+ * Check the intent to see if it resolves to a exported=false
+ * activity that doesn't share a uid with the authenticator.
+ *
+ * Otherwise the intent is considered unsafe in that it will be
+ * exploiting the fact that settings has system privileges.
+ */
+ if (isSafeIntent(pm, prefIntent, acccountType)) {
+ mFragment.getActivity().startActivityAsUser(
+ prefIntent, mUserHandle);
+ } else {
+ Log.e(TAG,
+ "Refusing to launch authenticator intent because"
+ + "it exploits Settings permissions: "
+ + prefIntent);
+ }
+ return true;
+ }
+ });
+ }
+ }
+ i++;
+ }
+ }
+
+ /**
+ * Determines if the supplied Intent is safe. A safe intent is one that is
+ * will launch a exported=true activity or owned by the same uid as the
+ * authenticator supplying the intent.
+ */
+ private boolean isSafeIntent(PackageManager pm, Intent intent, String acccountType) {
+ AuthenticatorDescription authDesc =
+ mAuthenticatorHelper.getAccountTypeDescription(acccountType);
+ ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mUserHandle.getIdentifier());
+ if (resolveInfo == null) {
+ return false;
+ }
+ ActivityInfo resolvedActivityInfo = resolveInfo.activityInfo;
+ ApplicationInfo resolvedAppInfo = resolvedActivityInfo.applicationInfo;
+ try {
+ if (resolvedActivityInfo.exported) {
+ if (resolvedActivityInfo.permission == null) {
+ return true; // exported activity without permission.
+ } else if (pm.checkPermission(resolvedActivityInfo.permission,
+ authDesc.packageName) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ ApplicationInfo authenticatorAppInf = pm.getApplicationInfo(authDesc.packageName, 0);
+ return resolvedAppInfo.uid == authenticatorAppInf.uid;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG,
+ "Intent considered unsafe due to exception.",
+ e);
+ return false;
+ }
+ }
+
+ /** Listens to a preference click event and starts a fragment */
+ private class FragmentStarter
+ implements Preference.OnPreferenceClickListener {
+ private final String mClass;
+ private final int mTitleRes;
+
+ /**
+ * @param className the class name of the fragment to be started.
+ * @param title the title resource id of the started preference panel.
+ */
+ public FragmentStarter(String className, int title) {
+ mClass = className;
+ mTitleRes = title;
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ ((SettingsActivity) mFragment.getActivity()).startPreferencePanel(
+ mClass, null, mTitleRes, null, null, 0);
+ // Hack: announce that the Google account preferences page is launching the location
+ // settings
+ if (mClass.equals(LocationSettings.class.getName())) {
+ Intent intent = new Intent(LAUNCHING_LOCATION_SETTINGS);
+ mFragment.getActivity().sendBroadcast(
+ intent, android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ return true;
+ }
+ }
+
+}
diff --git a/src/com/android/settings/accounts/ManageAccountsSettings.java b/src/com/android/settings/accounts/ManageAccountsSettings.java
index e6569e9..7c5ee00 100644
--- a/src/com/android/settings/accounts/ManageAccountsSettings.java
+++ b/src/com/android/settings/accounts/ManageAccountsSettings.java
@@ -18,26 +18,17 @@
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AuthenticatorDescription;
import android.app.ActionBar;
import android.app.Activity;
import android.content.ContentResolver;
-import android.content.Intent;
import android.content.SyncAdapterType;
import android.content.SyncInfo;
import android.content.SyncStatusInfo;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
-import android.support.v7.preference.Preference.OnPreferenceClickListener;
-import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
import android.util.ArraySet;
import android.util.Log;
@@ -53,7 +44,6 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
-import com.android.settings.location.LocationSettings;
import com.android.settingslib.accounts.AuthenticatorHelper;
import java.util.ArrayList;
@@ -66,15 +56,9 @@
/** Manages settings for Google Account. */
public class ManageAccountsSettings extends AccountPreferenceBase
implements AuthenticatorHelper.OnAccountsUpdateListener {
- private static final String ACCOUNT_KEY = "account"; // to pass to auth settings
public static final String KEY_ACCOUNT_TYPE = "account_type";
public static final String KEY_ACCOUNT_LABEL = "account_label";
- // Action name for the broadcast intent when the Google account preferences page is launching
- // the location settings.
- private static final String LAUNCHING_LOCATION_SETTINGS =
- "com.android.settings.accounts.LAUNCHING_LOCATION_SETTINGS";
-
private static final int MENU_SYNC_NOW_ID = Menu.FIRST;
private static final int MENU_SYNC_CANCEL_ID = Menu.FIRST + 1;
@@ -414,145 +398,7 @@
private void addAuthenticatorSettings() {
PreferenceScreen prefs = addPreferencesForType(mAccountType, getPreferenceScreen());
if (prefs != null) {
- updatePreferenceIntents(prefs);
- }
- }
-
- /** Listens to a preference click event and starts a fragment */
- private class FragmentStarter
- implements Preference.OnPreferenceClickListener {
- private final String mClass;
- private final int mTitleRes;
-
- /**
- * @param className the class name of the fragment to be started.
- * @param title the title resource id of the started preference panel.
- */
- public FragmentStarter(String className, int title) {
- mClass = className;
- mTitleRes = title;
- }
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- ((SettingsActivity) getActivity()).startPreferencePanel(
- mClass, null, mTitleRes, null, null, 0);
- // Hack: announce that the Google account preferences page is launching the location
- // settings
- if (mClass.equals(LocationSettings.class.getName())) {
- Intent intent = new Intent(LAUNCHING_LOCATION_SETTINGS);
- getActivity().sendBroadcast(
- intent, android.Manifest.permission.WRITE_SECURE_SETTINGS);
- }
- return true;
- }
- }
-
- /**
- * Recursively filters through the preference list provided by GoogleLoginService.
- *
- * This method removes all the invalid intent from the list, adds account name as extra into the
- * intent, and hack the location settings to start it as a fragment.
- */
- private void updatePreferenceIntents(PreferenceGroup prefs) {
- final PackageManager pm = getActivity().getPackageManager();
- for (int i = 0; i < prefs.getPreferenceCount(); ) {
- Preference pref = prefs.getPreference(i);
- if (pref instanceof PreferenceGroup) {
- updatePreferenceIntents((PreferenceGroup) pref);
- }
- Intent intent = pref.getIntent();
- if (intent != null) {
- // Hack. Launch "Location" as fragment instead of as activity.
- //
- // When "Location" is launched as activity via Intent, there's no "Up" button at the
- // top left, and if there's another running instance of "Location" activity, the
- // back stack would usually point to some other place so the user won't be able to
- // go back to the previous page by "back" key. Using fragment is a much easier
- // solution to those problems.
- //
- // If we set Intent to null and assign a fragment to the PreferenceScreen item here,
- // in order to make it work as expected, we still need to modify the container
- // PreferenceActivity, override onPreferenceStartFragment() and call
- // startPreferencePanel() there. In order to inject the title string there, more
- // dirty further hack is still needed. It's much easier and cleaner to listen to
- // preference click event here directly.
- if (intent.getAction().equals(
- android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)) {
- // The OnPreferenceClickListener overrides the click event completely. No intent
- // will get fired.
- pref.setOnPreferenceClickListener(new FragmentStarter(
- LocationSettings.class.getName(),
- R.string.location_settings_title));
- } else {
- ResolveInfo ri = pm.resolveActivityAsUser(intent,
- PackageManager.MATCH_DEFAULT_ONLY, mUserHandle.getIdentifier());
- if (ri == null) {
- prefs.removePreference(pref);
- continue;
- } else {
- intent.putExtra(ACCOUNT_KEY, mFirstAccount);
- intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- Intent prefIntent = preference.getIntent();
- /*
- * Check the intent to see if it resolves to a exported=false
- * activity that doesn't share a uid with the authenticator.
- *
- * Otherwise the intent is considered unsafe in that it will be
- * exploiting the fact that settings has system privileges.
- */
- if (isSafeIntent(pm, prefIntent)) {
- getActivity().startActivityAsUser(prefIntent, mUserHandle);
- } else {
- Log.e(TAG,
- "Refusing to launch authenticator intent because"
- + "it exploits Settings permissions: "
- + prefIntent);
- }
- return true;
- }
- });
- }
- }
- }
- i++;
- }
- }
-
- /**
- * Determines if the supplied Intent is safe. A safe intent is one that is
- * will launch a exported=true activity or owned by the same uid as the
- * authenticator supplying the intent.
- */
- private boolean isSafeIntent(PackageManager pm, Intent intent) {
- AuthenticatorDescription authDesc =
- mAuthenticatorHelper.getAccountTypeDescription(mAccountType);
- ResolveInfo resolveInfo =
- pm.resolveActivityAsUser(intent, 0, mUserHandle.getIdentifier());
- if (resolveInfo == null) {
- return false;
- }
- ActivityInfo resolvedActivityInfo = resolveInfo.activityInfo;
- ApplicationInfo resolvedAppInfo = resolvedActivityInfo.applicationInfo;
- try {
- if (resolvedActivityInfo.exported) {
- if (resolvedActivityInfo.permission == null) {
- return true; // exported activity without permission.
- } else if (pm.checkPermission(resolvedActivityInfo.permission,
- authDesc.packageName) == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- }
- ApplicationInfo authenticatorAppInf = pm.getApplicationInfo(authDesc.packageName, 0);
- return resolvedAppInfo.uid == authenticatorAppInf.uid;
- } catch (NameNotFoundException e) {
- Log.e(TAG,
- "Intent considered unsafe due to exception.",
- e);
- return false;
+ mAccountTypePreferenceLoader.updatePreferenceIntents(prefs, mAccountType, mFirstAccount);
}
}
diff --git a/src/com/android/settings/accounts/ManagedProfileSettings.java b/src/com/android/settings/accounts/ManagedProfileSettings.java
index 8c00be9..156631c 100644
--- a/src/com/android/settings/accounts/ManagedProfileSettings.java
+++ b/src/com/android/settings/accounts/ManagedProfileSettings.java
@@ -31,6 +31,7 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedSwitchPreference;
@@ -97,7 +98,8 @@
}
}
}
- return null;
+ // Return default managed profile for the current user.
+ return Utils.getManagedProfile(mUserManager);
}
private void loadDataAndPopulateUi() {
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 146e1ff..d5f7f78 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -381,6 +381,8 @@
AppFilter filter = new VolumeFilter(mVolumeUuid);
if (mStorageType == STORAGE_TYPE_MUSIC) {
filter = new CompoundFilter(ApplicationsState.FILTER_AUDIO, filter);
+ } else {
+ filter = new CompoundFilter(ApplicationsState.FILTER_OTHER_APPS, filter);
}
mApplications.setOverrideFilter(filter);
}
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index 372a353..514eaf2 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -15,6 +15,7 @@
*/
package com.android.settings.dashboard;
+import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
@@ -28,7 +29,6 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -61,15 +61,18 @@
private final IconCache mCache;
private final Context mContext;
private final MetricsFeatureProvider mMetricsFeatureProvider;
+ private final DashboardFeatureProvider mDashboardFeatureProvider;
private SuggestionParser mSuggestionParser;
+ private boolean mFirstFrameDrawn;
- @VisibleForTesting DashboardData mDashboardData;
+ @VisibleForTesting
+ DashboardData mDashboardData;
private View.OnClickListener mTileClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
//TODO: get rid of setTag/getTag
- ((SettingsActivity) mContext).openTile((Tile) v.getTag());
+ mDashboardFeatureProvider.openTileIntent((Activity) mContext, (Tile) v.getTag());
}
};
@@ -105,6 +108,8 @@
mContext = context;
mMetricsFeatureProvider = metricsFeatureProvider;
+ mDashboardFeatureProvider = FeatureFactory.getFactory(context)
+ .getDashboardFeatureProvider(context);
mCache = new IconCache(context);
mSuggestionParser = parser;
@@ -132,9 +137,9 @@
public void setCategoriesAndSuggestions(List<DashboardCategory> categories,
List<Tile> suggestions) {
// TODO: Better place for tinting?
- final TypedArray a = mContext.obtainStyledAttributes(new int[] {
- FeatureFactory.getFactory(mContext).getDashboardFeatureProvider(mContext).isEnabled()
- ? android.R.attr.colorControlNormal : android.R.attr.colorAccent });
+ final TypedArray a = mContext.obtainStyledAttributes(new int[]{
+ mDashboardFeatureProvider.isEnabled()
+ ? android.R.attr.colorControlNormal : android.R.attr.colorAccent});
int tintColor = a.getColor(0, mContext.getColor(android.R.color.white));
a.recycle();
for (int i = 0; i < categories.size(); i++) {
@@ -158,6 +163,15 @@
notifyDashboardDataChanged(prevData);
}
+ public void setCategory(List<DashboardCategory> category) {
+ final DashboardData prevData = mDashboardData;
+ Log.d(TAG, "adapter setCategory called");
+ mDashboardData = new DashboardData.Builder(prevData)
+ .setCategories(category)
+ .build();
+ notifyDashboardDataChanged(prevData);
+ }
+
public void setConditions(List<Condition> conditions) {
final DashboardData prevData = mDashboardData;
Log.d(TAG, "adapter setConditions called");
@@ -300,11 +314,12 @@
}
private void notifyDashboardDataChanged(DashboardData prevData) {
- if (prevData != null) {
+ if (mFirstFrameDrawn && prevData != null) {
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DashboardData
.ItemsDataDiffCallback(prevData.getItemList(), mDashboardData.getItemList()));
diffResult.dispatchUpdatesTo(this);
} else {
+ mFirstFrameDrawn = true;
notifyDataSetChanged();
}
}
@@ -405,12 +420,10 @@
final List<Tile> suggestions = mDashboardData.getSuggestions();
final List<DashboardCategory> categories = mDashboardData.getCategories();
if (suggestions != null) {
- outState.putParcelableArrayList(STATE_SUGGESTION_LIST,
- new ArrayList<Tile>(suggestions));
+ outState.putParcelableArrayList(STATE_SUGGESTION_LIST, new ArrayList<>(suggestions));
}
if (categories != null) {
- outState.putParcelableArrayList(STATE_CATEGORY_LIST,
- new ArrayList<DashboardCategory>(categories));
+ outState.putParcelableArrayList(STATE_CATEGORY_LIST, new ArrayList<>(categories));
}
outState.putInt(STATE_SUGGESTION_MODE, mDashboardData.getSuggestionMode());
}
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
index 2a5e800..7f91d16 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java
@@ -93,4 +93,9 @@
*/
String getExtraIntentAction();
+ /**
+ * Opens a tile to its destination intent.
+ */
+ void openTileIntent(Activity activity, Tile tile);
+
}
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 08372b0..223d050 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -21,15 +21,20 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.SettingsActivity;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.drawer.CategoryManager;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.ProfileSelectDialog;
+import com.android.settingslib.drawer.SettingsDrawerActivity;
import com.android.settingslib.drawer.Tile;
import java.util.ArrayList;
@@ -47,18 +52,20 @@
protected final Context mContext;
-
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
private final CategoryManager mCategoryManager;
public DashboardFeatureProviderImpl(Context context) {
mContext = context.getApplicationContext();
mCategoryManager = CategoryManager.get(context, getExtraIntentAction());
+ mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
@VisibleForTesting
DashboardFeatureProviderImpl(Context context, CategoryManager categoryManager) {
mContext = context.getApplicationContext();
mCategoryManager = categoryManager;
+ mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
@Override
@@ -149,14 +156,7 @@
intent.setAction(action);
}
pref.setOnPreferenceClickListener(preference -> {
- ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
- if (tile.userHandle == null) {
- activity.startActivityForResult(intent, 0);
- } else if (tile.userHandle.size() == 1) {
- activity.startActivityForResultAsUser(intent, 0, tile.userHandle.get(0));
- } else {
- ProfileSelectDialog.show(activity.getFragmentManager(), tile);
- }
+ launchIntentOrSelectProfile(activity, tile, intent);
return true;
});
}
@@ -188,4 +188,48 @@
public String getExtraIntentAction() {
return null;
}
+
+ @Override
+ public void openTileIntent(Activity activity, Tile tile) {
+ if (tile == null) {
+ Intent intent = new Intent(Settings.ACTION_SETTINGS).addFlags(
+ Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
+ return;
+ }
+
+ if (tile.intent == null) {
+ return;
+ }
+ final Intent intent = new Intent(tile.intent)
+ .putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ launchIntentOrSelectProfile(activity, tile, intent);
+ }
+
+ private void launchIntentOrSelectProfile(Activity activity, Tile tile, Intent intent) {
+ ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
+ if (tile.userHandle == null) {
+ logStartActivity(intent);
+ activity.startActivityForResult(intent, 0);
+ } else if (tile.userHandle.size() == 1) {
+ logStartActivity(intent);
+ activity.startActivityForResultAsUser(intent, 0, tile.userHandle.get(0));
+ } else {
+ ProfileSelectDialog.show(activity.getFragmentManager(), tile);
+ }
+ }
+
+ private void logStartActivity(Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ final ComponentName cn = intent.getComponent();
+ if (cn == null) {
+ return;
+ }
+ mMetricsFeatureProvider.action(mContext,
+ MetricsProto.MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+ cn.flattenToString());
+ }
}
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 74c8bfa..a5a4f43 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -27,6 +27,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -231,26 +232,25 @@
Log.d(TAG, "onViewCreated took "
+ (System.currentTimeMillis() - startTime) + " ms");
}
- rebuildUI();
+ rebuildUI(true /* rebuildSuggestions */);
}
- private void rebuildUI() {
- if (!isAdded()) {
- Log.w(TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
- return;
- }
-
- // recheck to see if any suggestions have been changed.
- new SuggestionLoader().execute();
- // Set categories on their own if loading suggestions takes too long.
- mHandler.postDelayed(() -> {
+ private void rebuildUI(boolean rebuildSuggestions) {
+ if (rebuildSuggestions) {
+ // recheck to see if any suggestions have been changed.
+ new SuggestionLoader().execute();
+ // Set categories on their own if loading suggestions takes too long.
+ mHandler.postDelayed(() -> {
+ updateCategoryAndSuggestion(null /* tiles */);
+ }, MAX_WAIT_MILLIS);
+ } else {
updateCategoryAndSuggestion(null /* tiles */);
- }, MAX_WAIT_MILLIS);
+ }
}
@Override
public void onCategoriesChanged() {
- rebuildUI();
+ rebuildUI(false /* rebuildSuggestions */);
}
@Override
@@ -264,7 +264,6 @@
}
private class SuggestionLoader extends AsyncTask<Void, Void, List<Tile>> {
-
@Override
protected List<Tile> doInBackground(Void... params) {
final Context context = getContext();
@@ -307,7 +306,7 @@
}
@VisibleForTesting
- void updateCategoryAndSuggestion(List<Tile> tiles) {
+ void updateCategoryAndSuggestion(List<Tile> suggestions) {
final Activity activity = getActivity();
if (activity == null) {
return;
@@ -319,10 +318,14 @@
List<DashboardCategory> categories = new ArrayList<>();
categories.add(mDashboardFeatureProvider.getTilesForCategory(
CategoryKey.CATEGORY_HOMEPAGE));
- mAdapter.setCategoriesAndSuggestions(categories, tiles);
+ if (suggestions != null) {
+ mAdapter.setCategoriesAndSuggestions(categories, suggestions);
+ } else {
+ mAdapter.setCategory(categories);
+ }
} else {
mAdapter.setCategoriesAndSuggestions(
- ((SettingsActivity) activity).getDashboardCategories(), tiles);
+ ((SettingsActivity) activity).getDashboardCategories(), suggestions);
}
}
}
diff --git a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
index 3170a87..769b69b 100644
--- a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
@@ -16,14 +16,13 @@
package com.android.settings.deviceinfo;
import android.content.Context;
-import android.support.v7.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.PreferenceController;
public class ManageStoragePreferenceController extends PreferenceController {
- public static final String KEY_MANAGE_STORAGE = "footer_preference";
+ public static final String KEY_MANAGE_STORAGE = "manage_storage";
public ManageStoragePreferenceController(Context context) {
super(context);
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index 6ec1b73..914a8fe 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -32,7 +32,6 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
-import com.android.settings.widget.FooterPreference;
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import java.util.ArrayList;
@@ -84,13 +83,6 @@
mSummaryController.updateBytes(usedBytes, totalSize);
mPreferenceController.setVolume(mVolume);
mPreferenceController.setSystemSize(systemSize);
-
- // Initialize the footer preference to go to the smart storage management.
- final FooterPreference pref = mFooterPreferenceMixin.createFooterPreference();
- pref.setTitle(R.string.storage_menu_manage);
- pref.setFragment("com.android.settings.deletionhelper.AutomaticStorageManagerSettings");
- pref.setIcon(R.drawable.ic_settings_storage);
- pref.setEnabled(true);
}
@Override
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index c1a2159..c7b0384 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -57,7 +57,7 @@
@Override
public void onAttach(Context context) {
super.onAttach(context);
- mProgressiveDisclosureMixin.setTileLimit(5);
+ mProgressiveDisclosureMixin.setTileLimit(6);
}
@Override
diff --git a/src/com/android/settings/search/DynamicIndexableContentMonitor.java b/src/com/android/settings/search/DynamicIndexableContentMonitor.java
index c5125bd..0cc2688 100644
--- a/src/com/android/settings/search/DynamicIndexableContentMonitor.java
+++ b/src/com/android/settings/search/DynamicIndexableContentMonitor.java
@@ -129,7 +129,7 @@
mContext = context;
mIndex = index;
- PACKAGE_CHANGE_MONITOR.register(context);
+ PACKAGE_CHANGE_MONITOR.registerMonitor(context);
mHasFeaturePrinting = context.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_PRINTING);
if (mHasFeaturePrinting) {
@@ -154,7 +154,7 @@
public void unregister(Activity activity, int loaderId) {
if (mIndex == null) return;
- PACKAGE_CHANGE_MONITOR.unregister();
+ PACKAGE_CHANGE_MONITOR.unregisterMonitor();
if (mHasFeaturePrinting) {
activity.getLoaderManager().destroyLoader(loaderId);
}
@@ -240,15 +240,31 @@
private static class PackageChangeMonitor extends PackageMonitor {
private static final String TAG = PackageChangeMonitor.class.getSimpleName();
- // Null if not initialized.
+ // Null if not initialized. Guarded by {@link #mLock}.
@Nullable private PackageManager mPackageManager;
+ private final Object mLock = new Object();
- public void register(Context context) {
- mPackageManager = context.getPackageManager();
+ public void registerMonitor(Context context) {
+ synchronized (mLock) {
+ if (mPackageManager != null) {
+ return;
+ }
+ mPackageManager = context.getPackageManager();
- // Start tracking packages. Use background thread for monitoring. Note that no need to
- // unregister this monitor. This should be alive while Settings app is running.
- register(context, null /* thread */, UserHandle.CURRENT, false);
+ // Start tracking packages. Use background thread for monitoring. Note that no need
+ // to unregister this monitor. This should be alive while Settings app is running.
+ super.register(context, null /* thread */, UserHandle.CURRENT, false);
+ }
+ }
+
+ public void unregisterMonitor() {
+ synchronized (mLock) {
+ if (mPackageManager == null) {
+ return;
+ }
+ super.unregister();
+ mPackageManager = null;
+ }
}
// Covers installed, appeared external storage with the package, upgraded.
diff --git a/src/com/android/settings/wifi/LinkablePreference.java b/src/com/android/settings/wifi/LinkablePreference.java
index 6b1b87d..5bf51ed 100644
--- a/src/com/android/settings/wifi/LinkablePreference.java
+++ b/src/com/android/settings/wifi/LinkablePreference.java
@@ -55,11 +55,15 @@
super.onBindViewHolder(view);
TextView textView = (TextView) view.findViewById(android.R.id.title);
- if (textView == null || mContentTitle == null || mClickListener == null) {
+ if (textView == null) {
+ return;
+ }
+ textView.setSingleLine(false);
+
+ if (mContentTitle == null || mClickListener == null) {
return;
}
- textView.setSingleLine(false);
StringBuilder contentBuilder = new StringBuilder().append(mContentTitle);
if (mContentDescription != null) {
contentBuilder.append("\n\n");
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index faf5ca4..c4b90c7 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -140,6 +140,10 @@
// should Next button only be enabled when we have a connection?
private boolean mEnableNextOnConnection;
+ // should see all networks instead of collapsing networks and showing mSeeAllNetworksPreference.
+ private boolean mSeeAllNetworks;
+ private static final int NETWORKS_TO_INITIALLY_SHOW = 5;
+
// Save the dialog details
private int mDialogMode;
private AccessPoint mDlgAccessPoint;
@@ -157,6 +161,7 @@
private PreferenceCategory mAccessPointsPreferenceCategory;
private PreferenceCategory mAdditionalSettingsPreferenceCategory;
private Preference mAddPreference;
+ private Preference mSeeAllNetworksPreference;
private Preference mConfigureWifiSettingsPreference;
private Preference mSavedNetworksPreference;
private LinkablePreference mStatusMessagePreference;
@@ -174,7 +179,9 @@
super.onViewCreated(view, savedInstanceState);
final Activity activity = getActivity();
if (activity != null) {
- mProgressHeader = (ProgressBar) setPinnedHeaderView(R.layout.wifi_progress_header);
+ if (!isUiRestricted()) {
+ mProgressHeader = (ProgressBar) setPinnedHeaderView(R.layout.wifi_progress_header);
+ }
}
}
@@ -196,10 +203,18 @@
mConfigureWifiSettingsPreference = findPreference(PREF_KEY_CONFIGURE_WIFI_SETTINGS);
mSavedNetworksPreference = findPreference(PREF_KEY_SAVED_NETWORKS);
+ if (isUiRestricted()) {
+ getPreferenceScreen().removePreference(mAdditionalSettingsPreferenceCategory);
+ }
+
Context prefContext = getPrefContext();
mAddPreference = new Preference(prefContext);
mAddPreference.setIcon(R.drawable.ic_menu_add_inset);
mAddPreference.setTitle(R.string.wifi_add_network);
+ mSeeAllNetworksPreference = new Preference(prefContext);
+ mSeeAllNetworksPreference.setIcon(R.drawable.ic_arrow_down_24dp);
+ mSeeAllNetworksPreference.setTitle(R.string.wifi_see_all_networks_button_title);
+ mSeeAllNetworks = false;
mStatusMessagePreference = new LinkablePreference(prefContext);
mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
@@ -524,6 +539,9 @@
}
} else if (preference == mAddPreference) {
onAddNetworkPressed();
+ } else if (preference == mSeeAllNetworksPreference) {
+ mSeeAllNetworks = true;
+ onAccessPointsChanged();
} else {
return super.onPreferenceTreeClick(preference);
}
@@ -635,8 +653,12 @@
cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);
int index = configureConnectedAccessPointPreferenceCategory(accessPoints) ? 1 : 0;
+ boolean fewerNetworksThanLimit =
+ accessPoints.size() <= index + NETWORKS_TO_INITIALLY_SHOW;
+ int numAccessPointsToShow = mSeeAllNetworks || fewerNetworksThanLimit
+ ? accessPoints.size() : index + NETWORKS_TO_INITIALLY_SHOW;
- for (; index < accessPoints.size(); index++) {
+ for (; index < numAccessPointsToShow; index++) {
AccessPoint accessPoint = accessPoints.get(index);
// Ignore access points that are out of range.
if (accessPoint.getLevel() != -1) {
@@ -682,15 +704,19 @@
pref.setOrder(index++);
pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
mAccessPointsPreferenceCategory.addPreference(pref);
- mAddPreference.setOrder(index++);
- mAccessPointsPreferenceCategory.addPreference(mAddPreference);
- setConfigureWifiSettingsVisibility();
} else {
- mAddPreference.setOrder(index++);
- mAccessPointsPreferenceCategory.addPreference(mAddPreference);
- setConfigureWifiSettingsVisibility();
setProgressBarVisible(false);
}
+ if (mSeeAllNetworks || fewerNetworksThanLimit) {
+ mAccessPointsPreferenceCategory.removePreference(mSeeAllNetworksPreference);
+ mAddPreference.setOrder(index);
+ mAccessPointsPreferenceCategory.addPreference(mAddPreference);
+ } else {
+ mAccessPointsPreferenceCategory.removePreference(mAddPreference);
+ mSeeAllNetworksPreference.setOrder(index);
+ mAccessPointsPreferenceCategory.addPreference(mSeeAllNetworksPreference);
+ }
+ setConfigureWifiSettingsVisibility();
if (mScanMenuItem != null) {
mScanMenuItem.setEnabled(true);
}
@@ -798,11 +824,11 @@
private void setOffMessage() {
if (isUiRestricted()) {
+ removeConnectedAccessPointPreference();
+ mAccessPointsPreferenceCategory.removeAll();
if (!isUiRestrictedByOnlyAdmin()) {
addMessagePreference(R.string.wifi_empty_list_user_restricted);
}
- removeConnectedAccessPointPreference();
- mAccessPointsPreferenceCategory.removeAll();
return;
}
diff --git a/tests/app/src/com/android/settings/deviceinfo/StorageDashboardFragmentEspressoTest.java b/tests/app/src/com/android/settings/deviceinfo/StorageDashboardFragmentEspressoTest.java
new file mode 100644
index 0000000..b43a5ba
--- /dev/null
+++ b/tests/app/src/com/android/settings/deviceinfo/StorageDashboardFragmentEspressoTest.java
@@ -0,0 +1,40 @@
+package com.android.settings.deviceinfo;
+
+import android.support.test.espresso.intent.rule.IntentsTestRule;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnitRunner;
+import com.android.settings.R;
+import com.android.settings.Settings.StorageDashboardActivity;
+import com.android.settings.deletionhelper.AutomaticStorageManagerSettings;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.intent.Intents.intended;
+import static android.support.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+
+@SmallTest
+public class StorageDashboardFragmentEspressoTest {
+
+ public static final String EXTRA_KEY = ":settings:show_fragment";
+
+ @Rule
+ public IntentsTestRule<StorageDashboardActivity> mActivityRule =
+ new IntentsTestRule<>(StorageDashboardActivity.class, true, true);
+
+ @Test
+ public void testStorageManagePreference_canClickTextView() throws InterruptedException {
+ // Click on the actual textbox instead of just somewhere in the preference
+ onView(withText(R.string.storage_menu_manage)).perform(click());
+
+ // Check that it worked by seeing if we switched screens
+ intended(hasExtra(equalTo(EXTRA_KEY),
+ containsString(AutomaticStorageManagerSettings.class.getName())));
+
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/SecuritySettingsTest.java b/tests/robotests/src/com/android/settings/SecuritySettingsTest.java
index 92214e3..51c0d9b 100644
--- a/tests/robotests/src/com/android/settings/SecuritySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/SecuritySettingsTest.java
@@ -16,14 +16,14 @@
package com.android.settings;
-import android.content.Context;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.IContentProvider;
-import android.provider.Settings;
+import android.content.pm.PackageManager;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
+import android.provider.Settings;
-import com.android.settings.SettingsRobolectricTestRunner;
-import com.android.settings.TestConfig;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.drawer.DashboardCategory;
@@ -46,7 +46,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -121,6 +121,27 @@
}
@Test
+ @Config(shadows = {
+ ShadowSecureSettings.class,
+ })
+ public void testSummaryProvider_hasFingerPrint_hasStaticSummary() {
+ // Package verifier state is set to disabled.
+ ShadowSecureSettings.putInt(null, Settings.Secure.PACKAGE_VERIFIER_STATE, -1);
+ final FingerprintManager fpm = mock(FingerprintManager.class);
+ when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+ .thenReturn(true);
+
+ // Cast to Object to workaround a robolectric casting bug
+ when((Object) mContext.getSystemService(FingerprintManager.class)).thenReturn(fpm);
+ when(fpm.isHardwareDetected()).thenReturn(true);
+
+ mSummaryProvider.setListening(true);
+
+ verify(mContext).getString(R.string.security_dashboard_summary);
+ }
+
+
+ @Test
public void testGetPackageVerifierSummary_nullInput() {
assertThat(mSummaryProvider.getPackageVerifierSummary(null)).isNull();
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
index 31090be..fd0ab4b 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
@@ -61,6 +62,8 @@
private AccountManager mAccountManager;
@Mock
private Preference mPreference;
+ @Mock
+ private PreferenceScreen mScreen;
private AccountDetailDashboardFragment mFragment;
private Context mContext;
@@ -125,9 +128,10 @@
new AuthenticatorDescription[0]);
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
when(mFragment.getContext()).thenReturn(mContext);
+ doReturn(mScreen).when(mFragment).getPreferenceScreen();
doReturn(mPreference).when(mFragment).findPreference(PREF_ACCOUNT_HEADER);
- mFragment.updateAccountHeader();
+ mFragment.updateUi();
verify(mPreference).setTitle("name1@abc.com");
}
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java b/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java
new file mode 100644
index 0000000..29f254d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/AccountTypePreferenceLoaderTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.accounts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.shadow.ShadowAccountManager;
+import com.android.settings.testutils.shadow.ShadowContentResolver;
+import com.android.settingslib.accounts.AuthenticatorHelper;
+
+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 org.robolectric.shadows.ShadowApplication;
+
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+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 AccountTypePreferenceLoaderTest {
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private AccountManager mAccountManager;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceFragment mPreferenceFragment;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private Context mContext;
+ private Account mAccount;
+ private AccountTypePreferenceLoader mPrefLoader;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowApplication shadowContext = ShadowApplication.getInstance();
+ shadowContext.setSystemService(Context.ACCOUNT_SERVICE, mAccountManager);
+ when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
+ new AuthenticatorDescription[0]);
+ when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
+ when(mPreferenceFragment.getActivity().getPackageManager()).thenReturn(mPackageManager);
+ mContext = shadowContext.getApplicationContext();
+ mAccount = new Account("name", "type");
+ final AuthenticatorHelper helper = new AuthenticatorHelper(mContext, UserHandle.CURRENT,
+ null /* OnAccountsUpdateListener */);
+ mPrefLoader = spy(new AccountTypePreferenceLoader(mPreferenceFragment, helper,
+ UserHandle.CURRENT));
+ }
+
+ @Test
+ @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
+ public void updatePreferenceIntents_shouldRunRecursively() {
+ final PreferenceManager preferenceManager = mock(PreferenceManager.class);
+ // Top level
+ PreferenceGroup prefRoot = spy(new PreferenceScreen(mContext, null));
+ when(prefRoot.getPreferenceManager()).thenReturn(preferenceManager);
+ Preference pref1 = mock(Preference.class);
+ PreferenceGroup prefGroup2 = spy(new PreferenceScreen(mContext, null));
+ when(prefGroup2.getPreferenceManager()).thenReturn(preferenceManager);
+ Preference pref3 = mock(Preference.class);
+ PreferenceGroup prefGroup4 = spy(new PreferenceScreen(mContext, null));
+ when(prefGroup4.getPreferenceManager()).thenReturn(preferenceManager);
+ prefRoot.addPreference(pref1);
+ prefRoot.addPreference(prefGroup2);
+ prefRoot.addPreference(pref3);
+ prefRoot.addPreference(prefGroup4);
+
+ // 2nd level
+ Preference pref21 = mock(Preference.class);
+ Preference pref22 = mock(Preference.class);
+ prefGroup2.addPreference(pref21);
+ prefGroup2.addPreference(pref22);
+ PreferenceGroup prefGroup41 = spy(new PreferenceScreen(mContext, null));
+ when(prefGroup41.getPreferenceManager()).thenReturn(preferenceManager);
+ Preference pref42 = mock(Preference.class);
+ prefGroup4.addPreference(prefGroup41);
+ prefGroup4.addPreference(pref42);
+
+ // 3rd level
+ Preference pref411 = mock(Preference.class);
+ Preference pref412 = mock(Preference.class);
+ prefGroup41.addPreference(pref411);
+ prefGroup41.addPreference(pref412);
+
+ final String acctType = "testType";
+ mPrefLoader.updatePreferenceIntents(prefRoot, acctType, mAccount);
+
+ verify(mPrefLoader).updatePreferenceIntents(prefGroup2, acctType, mAccount);
+ verify(mPrefLoader).updatePreferenceIntents(prefGroup4, acctType, mAccount);
+ verify(mPrefLoader).updatePreferenceIntents(prefGroup41, acctType, mAccount);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index 917c336..af720cb 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -27,9 +27,11 @@
import android.os.UserManager;
import android.support.v7.preference.Preference;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.CategoryManager;
import com.android.settingslib.drawer.DashboardCategory;
@@ -50,6 +52,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -67,12 +70,15 @@
private UserManager mUserManager;
@Mock
private CategoryManager mCategoryManager;
+ private FakeFeatureFactory mFeatureFactory;
private DashboardFeatureProviderImpl mImpl;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ FakeFeatureFactory.setupForTest(mActivity);
+ mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mActivity);
mImpl = new DashboardFeatureProviderImpl(mActivity);
}
@@ -141,6 +147,30 @@
}
@Test
+ public void bindPreference_noFragmentMetadataSingleUser_shouldBindToDirectLaunchIntent() {
+ final Preference preference = new Preference(
+ ShadowApplication.getInstance().getApplicationContext());
+ final Tile tile = new Tile();
+ tile.metaData = new Bundle();
+ tile.userHandle = new ArrayList<>();
+ tile.userHandle.add(mock(UserHandle.class));
+ tile.intent = new Intent();
+ tile.intent.setComponent(new ComponentName("pkg", "class"));
+
+ when(mActivity.getSystemService(Context.USER_SERVICE))
+ .thenReturn(mUserManager);
+
+ mImpl.bindPreferenceToTile(mActivity, preference, tile, "123", Preference.DEFAULT_ORDER);
+ preference.getOnPreferenceClickListener().onPreferenceClick(null);
+ verify(mFeatureFactory.metricsFeatureProvider).action(
+ any(Context.class),
+ eq(MetricsProto.MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
+ eq(tile.intent.getComponent().flattenToString()));
+ verify(mActivity)
+ .startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class));
+ }
+
+ @Test
public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() {
final Preference preference = new Preference(
ShadowApplication.getInstance().getApplicationContext());
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java
index 9627e2c..62866c9 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardSummaryTest.java
@@ -17,8 +17,8 @@
package com.android.settings.dashboard;
import android.app.Activity;
-
import android.support.v7.widget.LinearLayoutManager;
+
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.dashboard.conditional.ConditionManager;
@@ -33,6 +33,7 @@
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
+import static org.mockito.Matchers.anyList;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -90,4 +91,13 @@
mSummary.onConditionsChanged();
verify(mDashboard, never()).scrollToPosition(0);
}
+
+ @Test
+ public void onCategoryChanged_updateCategoryOnly() {
+ doReturn(mock(Activity.class)).when(mSummary).getActivity();
+ when(mDashboardFeatureProvider.isEnabled()).thenReturn(true);
+
+ mSummary.onCategoriesChanged();
+ verify(mAdapter).setCategory(anyList());
+ }
}
\ No newline at end of file