summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java23
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java105
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java256
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java186
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java29
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java175
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java (renamed from packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java)17
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java191
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java389
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java102
10 files changed, 1419 insertions, 54 deletions
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java
index 06a4a45b4853..8cd33a5b3f6c 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java
@@ -53,15 +53,6 @@ public class ActivityTile extends Tile {
}
@Override
- protected CharSequence getComponentLabel(Context context) {
- final PackageManager pm = context.getPackageManager();
- final ComponentInfo info = getComponentInfo(context);
- return info == null
- ? null
- : info.loadLabel(pm);
- }
-
- @Override
protected ComponentInfo getComponentInfo(Context context) {
if (mComponentInfo == null) {
final PackageManager pm = context.getApplicationContext().getPackageManager();
@@ -78,4 +69,18 @@ public class ActivityTile extends Tile {
}
return mComponentInfo;
}
+
+ @Override
+ protected CharSequence getComponentLabel(Context context) {
+ final PackageManager pm = context.getPackageManager();
+ final ComponentInfo info = getComponentInfo(context);
+ return info == null
+ ? null
+ : info.loadLabel(pm);
+ }
+
+ @Override
+ protected int getComponentIcon(ComponentInfo componentInfo) {
+ return componentInfo.icon;
+ }
}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
new file mode 100644
index 000000000000..b2ba5deee731
--- /dev/null
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.drawer;
+
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Description of a single dashboard tile which is generated from a content provider.
+ */
+public class ProviderTile extends Tile {
+ private static final String TAG = "ProviderTile";
+
+ private static final boolean DEBUG_TIMING = false;
+
+ private String mAuthority;
+ private String mKey;
+
+ public ProviderTile(ComponentInfo info, String category, Bundle metaData) {
+ super(info, category);
+ setMetaData(metaData);
+ mAuthority = ((ProviderInfo) info).authority;
+ mKey = metaData.getString(META_DATA_PREFERENCE_KEYHINT);
+ }
+
+ ProviderTile(Parcel in) {
+ super(in);
+ mAuthority = ((ProviderInfo) mComponentInfo).authority;
+ mKey = getMetaData().getString(META_DATA_PREFERENCE_KEYHINT);
+ }
+
+ @Override
+ public int getId() {
+ return Objects.hash(mAuthority, mKey);
+ }
+
+ @Override
+ public String getDescription() {
+ return mAuthority + "/" + mKey;
+ }
+
+ @Override
+ protected ComponentInfo getComponentInfo(Context context) {
+ if (mComponentInfo == null) {
+ final long startTime = System.currentTimeMillis();
+ final PackageManager pm = context.getApplicationContext().getPackageManager();
+ final Intent intent = getIntent();
+ final List<ResolveInfo> infoList =
+ pm.queryIntentContentProviders(intent, 0 /* flags */);
+ if (infoList != null && !infoList.isEmpty()) {
+ final ProviderInfo providerInfo = infoList.get(0).providerInfo;
+ mComponentInfo = providerInfo;
+ setMetaData(TileUtils.getSwitchDataFromProvider(context, providerInfo.authority,
+ mKey));
+ } else {
+ Log.e(TAG, "Cannot find package info for "
+ + intent.getComponent().flattenToString());
+ }
+
+ if (DEBUG_TIMING) {
+ Log.d(TAG, "getComponentInfo took "
+ + (System.currentTimeMillis() - startTime) + " ms");
+ }
+ }
+ return mComponentInfo;
+ }
+
+ @Override
+ protected CharSequence getComponentLabel(Context context) {
+ // Getting provider label for a tile title isn't supported.
+ return null;
+ }
+
+ @Override
+ protected int getComponentIcon(ComponentInfo info) {
+ // Getting provider icon for a tile title isn't supported.
+ return 0;
+ }
+}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java
new file mode 100644
index 000000000000..e48da8608780
--- /dev/null
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.drawer;
+
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_SUMMARY;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_TITLE;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_IS_CHECKED;
+import static com.android.settingslib.drawer.TileUtils.EXTRA_CATEGORY_KEY;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+/**
+ * A controller that manages events for switch.
+ */
+public abstract class SwitchController {
+
+ private String mAuthority;
+
+ /**
+ * Returns the key for this switch.
+ */
+ public abstract String getSwitchKey();
+
+ /**
+ * Returns the {@link MetaData} for this switch.
+ */
+ protected abstract MetaData getMetaData();
+
+ /**
+ * Returns the checked state of this switch.
+ */
+ protected abstract boolean isChecked();
+
+ /**
+ * Called when the checked state of this switch is changed.
+ *
+ * @return true if the checked state was successfully changed, otherwise false
+ */
+ protected abstract boolean onCheckedChanged(boolean checked);
+
+ /**
+ * Returns the error message which will be toasted when {@link #onCheckedChanged} returns false.
+ */
+ protected abstract String getErrorMessage(boolean attemptedChecked);
+
+ /**
+ * Notify registered observers that title was updated and attempt to sync changes.
+ */
+ public void notifyTitleChanged(Context context) {
+ if (this instanceof DynamicTitle) {
+ notifyChanged(context, METHOD_GET_DYNAMIC_TITLE);
+ }
+ }
+
+ /**
+ * Notify registered observers that summary was updated and attempt to sync changes.
+ */
+ public void notifySummaryChanged(Context context) {
+ if (this instanceof DynamicSummary) {
+ notifyChanged(context, METHOD_GET_DYNAMIC_SUMMARY);
+ }
+ }
+
+ /**
+ * Notify registered observers that checked state was updated and attempt to sync changes.
+ */
+ public void notifyCheckedChanged(Context context) {
+ notifyChanged(context, METHOD_IS_CHECKED);
+ }
+
+ void setAuthority(String authority) {
+ mAuthority = authority;
+ }
+
+ Bundle getBundle() {
+ final MetaData metaData = getMetaData();
+ if (metaData == null) {
+ throw new IllegalArgumentException("Should not return null in getMetaData()");
+ }
+
+ final Bundle bundle = metaData.build();
+ final String uriString = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(mAuthority)
+ .build()
+ .toString();
+ bundle.putString(META_DATA_PREFERENCE_KEYHINT, getSwitchKey());
+ bundle.putString(META_DATA_PREFERENCE_SWITCH_URI, uriString);
+ if (this instanceof ProviderIcon) {
+ bundle.putString(META_DATA_PREFERENCE_ICON_URI, uriString);
+ }
+ if (this instanceof DynamicTitle) {
+ bundle.putString(META_DATA_PREFERENCE_TITLE_URI, uriString);
+ }
+ if (this instanceof DynamicSummary) {
+ bundle.putString(META_DATA_PREFERENCE_SUMMARY_URI, uriString);
+ }
+ return bundle;
+ }
+
+ private void notifyChanged(Context context, String method) {
+ final Uri uri = TileUtils.buildUri(mAuthority, method, getSwitchKey());
+ context.getContentResolver().notifyChange(uri, null);
+ }
+
+ /**
+ * Collects all meta data of the item.
+ */
+ protected static class MetaData {
+ private String mCategory;
+ private int mOrder;
+ @DrawableRes
+ private int mIcon;
+ private int mIconBackgroundHint;
+ private int mIconBackgroundArgb;
+ private Boolean mIconTintable;
+ @StringRes
+ private int mTitleId;
+ private String mTitle;
+ @StringRes
+ private int mSummaryId;
+ private String mSummary;
+
+ /**
+ * @param category the category of the switch. This value must be from {@link CategoryKey}.
+ */
+ public MetaData(@NonNull String category) {
+ mCategory = category;
+ }
+
+ /**
+ * Set the order of the item that should be displayed on screen. Bigger value items displays
+ * closer on top.
+ */
+ public MetaData setOrder(int order) {
+ mOrder = order;
+ return this;
+ }
+
+ /** Set the icon that should be displayed for the item. */
+ public MetaData setIcon(@DrawableRes int icon) {
+ mIcon = icon;
+ return this;
+ }
+
+ /** Set the icon background color. The value may or may not be used by Settings app. */
+ public MetaData setIconBackgoundHint(int hint) {
+ mIconBackgroundHint = hint;
+ return this;
+ }
+
+ /** Set the icon background color as raw ARGB. */
+ public MetaData setIconBackgoundArgb(int argb) {
+ mIconBackgroundArgb = argb;
+ return this;
+ }
+
+ /** Specify whether the icon is tintable. */
+ public MetaData setIconTintable(boolean tintable) {
+ mIconTintable = tintable;
+ return this;
+ }
+
+ /** Set the title that should be displayed for the item. */
+ public MetaData setTitle(@StringRes int id) {
+ mTitleId = id;
+ return this;
+ }
+
+ /** Set the title that should be displayed for the item. */
+ public MetaData setTitle(String title) {
+ mTitle = title;
+ return this;
+ }
+
+ /** Set the summary text that should be displayed for the item. */
+ public MetaData setSummary(@StringRes int id) {
+ mSummaryId = id;
+ return this;
+ }
+
+ /** Set the summary text that should be displayed for the item. */
+ public MetaData setSummary(String summary) {
+ mSummary = summary;
+ return this;
+ }
+
+ private Bundle build() {
+ final Bundle bundle = new Bundle();
+ bundle.putString(EXTRA_CATEGORY_KEY, mCategory);
+
+ if (mOrder != 0) {
+ bundle.putInt(META_DATA_KEY_ORDER, mOrder);
+ }
+
+ if (mIcon != 0) {
+ bundle.putInt(META_DATA_PREFERENCE_ICON, mIcon);
+ }
+ if (mIconBackgroundHint != 0) {
+ bundle.putInt(META_DATA_PREFERENCE_ICON_BACKGROUND_HINT, mIconBackgroundHint);
+ }
+ if (mIconBackgroundArgb != 0) {
+ bundle.putInt(META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB, mIconBackgroundArgb);
+ }
+ if (mIconTintable != null) {
+ bundle.putBoolean(META_DATA_PREFERENCE_ICON_TINTABLE, mIconTintable);
+ }
+
+ if (mTitleId != 0) {
+ bundle.putInt(META_DATA_PREFERENCE_TITLE, mTitleId);
+ } else if (mTitle != null) {
+ bundle.putString(META_DATA_PREFERENCE_TITLE, mTitle);
+ }
+
+ if (mSummaryId != 0) {
+ bundle.putInt(META_DATA_PREFERENCE_SUMMARY, mSummaryId);
+ } else if (mSummary != null) {
+ bundle.putString(META_DATA_PREFERENCE_SUMMARY, mSummary);
+ }
+ return bundle;
+ }
+ }
+}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
new file mode 100644
index 000000000000..a05c7d5d3b51
--- /dev/null
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.drawer;
+
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An abstract class for injecting switches to Settings.
+ */
+public abstract class SwitchesProvider extends ContentProvider {
+ private static final String TAG = "SwitchesProvider";
+
+ public static final String METHOD_GET_SWITCH_DATA = "getSwitchData";
+ public static final String METHOD_GET_PROVIDER_ICON = "getProviderIcon";
+ public static final String METHOD_GET_DYNAMIC_TITLE = "getDynamicTitle";
+ public static final String METHOD_GET_DYNAMIC_SUMMARY = "getDynamicSummary";
+ public static final String METHOD_IS_CHECKED = "isChecked";
+ public static final String METHOD_ON_CHECKED_CHANGED = "onCheckedChanged";
+
+ public static final String EXTRA_SWITCH_DATA = "switch_data";
+ public static final String EXTRA_SWITCH_CHECKED_STATE = "checked_state";
+ public static final String EXTRA_SWITCH_SET_CHECKED_ERROR = "set_checked_error";
+ public static final String EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE = "set_checked_error_message";
+
+ private String mAuthority;
+ private final Map<String, SwitchController> mControllerMap = new LinkedHashMap<>();
+ private final List<Bundle> mSwitchList = new ArrayList<>();
+
+ /**
+ * Get a list of {@link SwitchController} for this provider.
+ */
+ protected abstract List<SwitchController> createSwitchControllers();
+
+ @Override
+ public void attachInfo(Context context, ProviderInfo info) {
+ mAuthority = info.authority;
+ Log.i(TAG, mAuthority);
+ super.attachInfo(context, info);
+ }
+
+ @Override
+ public boolean onCreate() {
+ final List<SwitchController> controllers = createSwitchControllers();
+ if (controllers == null || controllers.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+
+ controllers.forEach(controller -> {
+ final String key = controller.getSwitchKey();
+ if (TextUtils.isEmpty(key)) {
+ throw new NullPointerException("Switch key cannot be null: "
+ + controller.getClass().getSimpleName());
+ } else if (mControllerMap.containsKey(key)) {
+ throw new IllegalArgumentException("Switch key " + key + " is duplicated by: "
+ + controller.getClass().getSimpleName());
+ }
+
+ controller.setAuthority(mAuthority);
+ mControllerMap.put(key, controller);
+ mSwitchList.add(controller.getBundle());
+ });
+ return true;
+ }
+
+ @Override
+ public Bundle call(String method, String uriString, Bundle extras) {
+ final Bundle bundle = new Bundle();
+ final String key = extras != null
+ ? extras.getString(META_DATA_PREFERENCE_KEYHINT)
+ : null;
+ if (TextUtils.isEmpty(key)) {
+ if (METHOD_GET_SWITCH_DATA.equals(method)) {
+ bundle.putParcelableList(EXTRA_SWITCH_DATA, mSwitchList);
+ return bundle;
+ }
+ return null;
+ }
+
+ final SwitchController controller = mControllerMap.get(key);
+ if (controller == null) {
+ return null;
+ }
+
+ switch (method) {
+ case METHOD_GET_SWITCH_DATA:
+ return controller.getBundle();
+ case METHOD_GET_PROVIDER_ICON:
+ if (controller instanceof ProviderIcon) {
+ return ((ProviderIcon) controller).getProviderIcon();
+ }
+ break;
+ case METHOD_GET_DYNAMIC_TITLE:
+ if (controller instanceof DynamicTitle) {
+ bundle.putString(META_DATA_PREFERENCE_TITLE,
+ ((DynamicTitle) controller).getDynamicTitle());
+ return bundle;
+ }
+ break;
+ case METHOD_GET_DYNAMIC_SUMMARY:
+ if (controller instanceof DynamicSummary) {
+ bundle.putString(META_DATA_PREFERENCE_SUMMARY,
+ ((DynamicSummary) controller).getDynamicSummary());
+ return bundle;
+ }
+ break;
+ case METHOD_IS_CHECKED:
+ bundle.putBoolean(EXTRA_SWITCH_CHECKED_STATE, controller.isChecked());
+ return bundle;
+ case METHOD_ON_CHECKED_CHANGED:
+ return onCheckedChanged(extras.getBoolean(EXTRA_SWITCH_CHECKED_STATE), controller);
+ }
+ return null;
+ }
+
+ private Bundle onCheckedChanged(boolean checked, SwitchController controller) {
+ final boolean success = controller.onCheckedChanged(checked);
+ final Bundle bundle = new Bundle();
+ bundle.putBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR, !success);
+ if (success) {
+ if (controller instanceof DynamicSummary) {
+ controller.notifySummaryChanged(getContext());
+ }
+ } else {
+ bundle.putString(EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE,
+ controller.getErrorMessage(checked));
+ }
+ return bundle;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index 722f734b8021..1e4c7cac4404 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -23,6 +23,7 @@ import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE_URI;
import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
@@ -79,6 +80,7 @@ public abstract class Tile implements Parcelable {
}
Tile(Parcel in) {
+ final boolean isProviderTile = in.readBoolean();
mComponentPackage = in.readString();
mComponentName = in.readString();
mIntent = new Intent().setClassName(mComponentPackage, mComponentName);
@@ -97,6 +99,7 @@ public abstract class Tile implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(this instanceof ProviderTile);
dest.writeString(mComponentPackage);
dest.writeString(mComponentName);
final int size = userHandle.size();
@@ -118,6 +121,12 @@ public abstract class Tile implements Parcelable {
*/
public abstract String getDescription();
+ protected abstract ComponentInfo getComponentInfo(Context context);
+
+ protected abstract CharSequence getComponentLabel(Context context);
+
+ protected abstract int getComponentIcon(ComponentInfo info);
+
public String getPackageName() {
return mComponentPackage;
}
@@ -164,6 +173,13 @@ public abstract class Tile implements Parcelable {
}
/**
+ * Check whether tile has a switch.
+ */
+ public boolean hasSwitch() {
+ return mMetaData != null && mMetaData.containsKey(META_DATA_PREFERENCE_SWITCH_URI);
+ }
+
+ /**
* Title of the tile that is shown to the user.
*/
public CharSequence getTitle(Context context) {
@@ -195,8 +211,6 @@ public abstract class Tile implements Parcelable {
return title;
}
- protected abstract CharSequence getComponentLabel(Context context);
-
/**
* Overrides the summary. This can happen when injected tile wants to provide dynamic summary.
*/
@@ -293,7 +307,7 @@ public abstract class Tile implements Parcelable {
// ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this
// level is too complex because we don't have a strong threading contract for this class
if (!mMetaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
- iconResId = componentInfo.icon;
+ iconResId = getComponentIcon(componentInfo);
}
}
if (iconResId != 0) {
@@ -345,11 +359,12 @@ public abstract class Tile implements Parcelable {
}
}
- protected abstract ComponentInfo getComponentInfo(Context context);
-
public static final Creator<Tile> CREATOR = new Creator<Tile>() {
public Tile createFromParcel(Parcel source) {
- return new ActivityTile(source);
+ final boolean isProviderTile = source.readBoolean();
+ // reset the Parcel pointer before delegating to the real constructor.
+ source.setDataPosition(0);
+ return isProviderTile ? new ProviderTile(source) : new ActivityTile(source);
}
public Tile[] newArray(int size) {
@@ -358,7 +373,7 @@ public abstract class Tile implements Parcelable {
};
/**
- * Check whether title is only have primary profile
+ * Check whether tile only has primary profile.
*/
public boolean isPrimaryProfileOnly() {
String profile = mMetaData != null
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index b9daf7fcab4e..71ffff780b21 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -16,12 +16,14 @@
package com.android.settingslib.drawer;
import android.app.ActivityManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -30,6 +32,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings.Global;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -96,13 +99,12 @@ public class TileUtils {
* {@link #EXTRA_SETTINGS_ACTION}
* The value must be from {@link CategoryKey}.
*/
- private static final String EXTRA_CATEGORY_KEY = "com.android.settings.category";
+ static final String EXTRA_CATEGORY_KEY = "com.android.settings.category";
/**
* The key used to get the package name of the icon resource for the preference.
*/
- private static final String EXTRA_PREFERENCE_ICON_PACKAGE =
- "com.android.settings.icon_package";
+ static final String EXTRA_PREFERENCE_ICON_PACKAGE = "com.android.settings.icon_package";
/**
* Name of the meta-data item that should be set in the AndroidManifest.xml
@@ -189,6 +191,17 @@ public class TileUtils {
"com.android.settings.summary_uri";
/**
+ * Name of the meta-data item that should be set in the AndroidManifest.xml
+ * to specify the content provider providing the switch that should be displayed for the
+ * preference.
+ *
+ * This works with {@link #META_DATA_PREFERENCE_KEYHINT} which should also be set in the
+ * AndroidManifest.xml
+ */
+ public static final String META_DATA_PREFERENCE_SWITCH_URI =
+ "com.android.settings.switch_uri";
+
+ /**
* Value for {@link #META_DATA_KEY_PROFILE}. When the device has a managed profile,
* the app will always be run in the primary profile.
*
@@ -279,6 +292,7 @@ public class TileUtils {
intent.setPackage(SETTING_PKG);
}
getActivityTiles(context, user, addedCache, defaultCategory, outTiles, intent);
+ getProviderTiles(context, user, addedCache, defaultCategory, outTiles, intent);
}
private static void getActivityTiles(Context context,
@@ -298,6 +312,30 @@ public class TileUtils {
}
}
+ private static void getProviderTiles(Context context,
+ UserHandle user, Map<Pair<String, String>, Tile> addedCache,
+ String defaultCategory, List<Tile> outTiles, Intent intent) {
+ final PackageManager pm = context.getPackageManager();
+ final List<ResolveInfo> results = pm.queryIntentContentProvidersAsUser(intent,
+ 0 /* flags */, user.getIdentifier());
+ for (ResolveInfo resolved : results) {
+ if (!resolved.system) {
+ // Do not allow any app to add to settings, only system ones.
+ continue;
+ }
+ final ProviderInfo providerInfo = resolved.providerInfo;
+ final List<Bundle> switchData = getSwitchDataFromProvider(context,
+ providerInfo.authority);
+ if (switchData == null || switchData.isEmpty()) {
+ continue;
+ }
+ for (Bundle metaData : switchData) {
+ getTile(user, addedCache, defaultCategory, outTiles, intent, metaData,
+ providerInfo);
+ }
+ }
+ }
+
private static void getTile(UserHandle user, Map<Pair<String, String>, Tile> addedCache,
String defaultCategory, List<Tile> outTiles, Intent intent, Bundle metaData,
ComponentInfo componentInfo) {
@@ -313,10 +351,16 @@ public class TileUtils {
categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
}
- final Pair<String, String> key = new Pair<>(componentInfo.packageName, componentInfo.name);
+ final boolean isProvider = componentInfo instanceof ProviderInfo;
+ final Pair<String, String> key = isProvider
+ ? new Pair<>(((ProviderInfo) componentInfo).authority,
+ metaData.getString(META_DATA_PREFERENCE_KEYHINT))
+ : new Pair<>(componentInfo.packageName, componentInfo.name);
Tile tile = addedCache.get(key);
if (tile == null) {
- tile = new ActivityTile(componentInfo, categoryKey);
+ tile = isProvider
+ ? new ProviderTile(componentInfo, categoryKey, metaData)
+ : new ActivityTile(componentInfo, categoryKey);
addedCache.put(key, tile);
} else {
tile.setMetaData(metaData);
@@ -330,20 +374,75 @@ public class TileUtils {
}
}
+ /** Returns the switch data of the key specified from the provider */
+ // TODO(b/144732809): rearrange methods by access level modifiers
+ static Bundle getSwitchDataFromProvider(Context context, String authority, String key) {
+ final Map<String, IContentProvider> providerMap = new ArrayMap<>();
+ final Uri uri = buildUri(authority, SwitchesProvider.METHOD_GET_SWITCH_DATA, key);
+ return getBundleFromUri(context, uri, providerMap, null /* bundle */);
+ }
+
+ /** Returns all switch data from the provider */
+ private static List<Bundle> getSwitchDataFromProvider(Context context, String authority) {
+ final Map<String, IContentProvider> providerMap = new ArrayMap<>();
+ final Uri uri = buildUri(authority, SwitchesProvider.METHOD_GET_SWITCH_DATA);
+ final Bundle result = getBundleFromUri(context, uri, providerMap, null /* bundle */);
+ return result != null
+ ? result.getParcelableArrayList(SwitchesProvider.EXTRA_SWITCH_DATA)
+ : null;
+ }
+
/**
* Returns the complete uri from the meta data key of the tile.
-
+ *
+ * A complete uri should contain at least one path segment and be one of the following types:
+ * content://authority/method
+ * content://authority/method/key
+ *
+ * If the uri from the tile is not complete, build a uri by the default method and the
+ * preference key.
+ *
* @param tile Tile which contains meta data
* @param metaDataKey Key mapping to the uri in meta data
+ * @param defaultMethod Method to be attached to the uri by default if it has no path segment
* @return Uri associated with the key
*/
- public static Uri getCompleteUri(Tile tile, String metaDataKey) {
+ public static Uri getCompleteUri(Tile tile, String metaDataKey, String defaultMethod) {
final String uriString = tile.getMetaData().getString(metaDataKey);
if (TextUtils.isEmpty(uriString)) {
return null;
}
- return Uri.parse(uriString);
+ final Uri uri = Uri.parse(uriString);
+ final List<String> pathSegments = uri.getPathSegments();
+ if (pathSegments != null && !pathSegments.isEmpty()) {
+ return uri;
+ }
+
+ final String key = tile.getMetaData().getString(META_DATA_PREFERENCE_KEYHINT);
+ if (TextUtils.isEmpty(key)) {
+ Log.w(LOG_TAG, "Please specify the meta-data " + META_DATA_PREFERENCE_KEYHINT
+ + " in AndroidManifest.xml for " + uriString);
+ return buildUri(uri.getAuthority(), defaultMethod);
+ }
+ return buildUri(uri.getAuthority(), defaultMethod, key);
+ }
+
+ static Uri buildUri(String authority, String method, String key) {
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(authority)
+ .appendPath(method)
+ .appendPath(key)
+ .build();
+ }
+
+ private static Uri buildUri(String authority, String method) {
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(authority)
+ .appendPath(method)
+ .build();
}
/**
@@ -357,7 +456,7 @@ public class TileUtils {
*/
public static Pair<String, Integer> getIconFromUri(Context context, String packageName,
Uri uri, Map<String, IContentProvider> providerMap) {
- final Bundle bundle = getBundleFromUri(context, uri, providerMap, null);
+ final Bundle bundle = getBundleFromUri(context, uri, providerMap, null /* bundle */);
if (bundle == null) {
return null;
}
@@ -388,16 +487,50 @@ public class TileUtils {
*/
public static String getTextFromUri(Context context, Uri uri,
Map<String, IContentProvider> providerMap, String key) {
- final Bundle bundle = getBundleFromUri(context, uri, providerMap, null);
+ final Bundle bundle = getBundleFromUri(context, uri, providerMap, null /* bundle */);
return (bundle != null) ? bundle.getString(key) : null;
}
+ /**
+ * Gets boolean associated with the input key from the content provider.
+ *
+ * @param context context
+ * @param uri URI for the content provider
+ * @param providerMap Maps URI authorities to providers
+ * @param key Key mapping to the text in bundle returned by the content provider
+ * @return Boolean associated with the key, if returned by the content provider
+ */
+ public static boolean getBooleanFromUri(Context context, Uri uri,
+ Map<String, IContentProvider> providerMap, String key) {
+ final Bundle bundle = getBundleFromUri(context, uri, providerMap, null /* bundle */);
+ return (bundle != null) ? bundle.getBoolean(key) : false;
+ }
+
+ /**
+ * Puts boolean associated with the input key to the content provider.
+ *
+ * @param context context
+ * @param uri URI for the content provider
+ * @param providerMap Maps URI authorities to providers
+ * @param key Key mapping to the text in bundle returned by the content provider
+ * @param value Boolean associated with the key
+ * @return Bundle associated with the action, if returned by the content provider
+ */
+ public static Bundle putBooleanToUri(Context context, Uri uri,
+ Map<String, IContentProvider> providerMap, String key, boolean value) {
+ final Bundle bundle = new Bundle();
+ bundle.putBoolean(key, value);
+ return getBundleFromUri(context, uri, providerMap, bundle);
+ }
+
private static Bundle getBundleFromUri(Context context, Uri uri,
Map<String, IContentProvider> providerMap, Bundle bundle) {
- if (uri == null) {
+ final Pair<String, String> args = getMethodAndKey(uri);
+ if (args == null) {
return null;
}
- final String method = getMethodFromUri(uri);
+ final String method = args.first;
+ final String key = args.second;
if (TextUtils.isEmpty(method)) {
return null;
}
@@ -405,6 +538,12 @@ public class TileUtils {
if (provider == null) {
return null;
}
+ if (!TextUtils.isEmpty(key)) {
+ if (bundle == null) {
+ bundle = new Bundle();
+ }
+ bundle.putString(META_DATA_PREFERENCE_KEYHINT, key);
+ }
try {
return provider.call(context.getPackageName(), context.getFeatureId(),
uri.getAuthority(), method, uri.toString(), bundle);
@@ -428,15 +567,17 @@ public class TileUtils {
return providerMap.get(authority);
}
- /** Returns the first path segment of the uri if it exists as the method, otherwise null. */
- private static String getMethodFromUri(Uri uri) {
+ /** Returns method and key of the complete uri. */
+ private static Pair<String, String> getMethodAndKey(Uri uri) {
if (uri == null) {
return null;
}
- List<String> pathSegments = uri.getPathSegments();
- if ((pathSegments == null) || pathSegments.isEmpty()) {
+ final List<String> pathSegments = uri.getPathSegments();
+ if (pathSegments == null || pathSegments.isEmpty()) {
return null;
}
- return pathSegments.get(0);
+ final String method = pathSegments.get(0);
+ final String key = pathSegments.size() > 1 ? pathSegments.get(1) : null;
+ return Pair.create(method, key);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
index 2664ecd17dd3..4f8ecf8f8823 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.settingslib.drawer;
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
@@ -25,7 +40,7 @@ import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowPackageManager;
@RunWith(RobolectricTestRunner.class)
-public class TileTest {
+public class ActivityTileTest {
private Context mContext;
private ActivityInfo mActivityInfo;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
new file mode 100644
index 000000000000..abfb407d749e
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.drawer;
+
+import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
+import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
+import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowPackageManager;
+
+@RunWith(RobolectricTestRunner.class)
+public class ProviderTileTest {
+
+ @Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ private Context mContext;
+ private ProviderInfo mProviderInfo;
+ private Bundle mMetaData;
+ private Tile mTile;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mProviderInfo = new ProviderInfo();
+ mProviderInfo.applicationInfo = new ApplicationInfo();
+ mProviderInfo.packageName = mContext.getPackageName();
+ mProviderInfo.name = "abc";
+ mProviderInfo.authority = "authority";
+ mMetaData = new Bundle();
+ mMetaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
+ mMetaData.putString(META_DATA_PREFERENCE_TITLE, "title");
+ mMetaData.putInt(META_DATA_PREFERENCE_ICON, com.android.internal.R.drawable.ic_plus);
+ mTile = new ProviderTile(mProviderInfo, "category", mMetaData);
+ }
+
+ @Test
+ public void isPrimaryProfileOnly_profilePrimary_shouldReturnTrue() {
+ mMetaData.putString(META_DATA_KEY_PROFILE, PROFILE_PRIMARY);
+ assertThat(mTile.isPrimaryProfileOnly()).isTrue();
+ }
+
+ @Test
+ public void isPrimaryProfileOnly_profileAll_shouldReturnFalse() {
+ mMetaData.putString(META_DATA_KEY_PROFILE, PROFILE_ALL);
+ assertThat(mTile.isPrimaryProfileOnly()).isFalse();
+ }
+
+ @Test
+ public void isPrimaryProfileOnly_noExplicitValue_shouldReturnFalse() {
+ assertThat(mTile.isPrimaryProfileOnly()).isFalse();
+ }
+
+ @Test
+ public void getIcon_noContextOrMetadata_shouldThrowNullPointerException() {
+ thrown.expect(NullPointerException.class);
+
+ final Tile tile = new ProviderTile(mProviderInfo, "category", null);
+ }
+
+ @Test
+ public void getIcon_hasIconMetadata_returnIcon() {
+ mMetaData.putInt(META_DATA_PREFERENCE_ICON, android.R.drawable.ic_info);
+
+ assertThat(mTile.getIcon(RuntimeEnvironment.application).getResId())
+ .isEqualTo(android.R.drawable.ic_info);
+ }
+
+ @Test
+ public void isIconTintable_hasMetadata_shouldReturnIconTintableMetadata() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ mMetaData.putBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE, false);
+ assertThat(tile.isIconTintable(RuntimeEnvironment.application)).isFalse();
+
+ mMetaData.putBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE, true);
+ assertThat(tile.isIconTintable(RuntimeEnvironment.application)).isTrue();
+ }
+
+ @Test
+ public void isIconTintable_noIcon_shouldReturnFalse() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.isIconTintable(RuntimeEnvironment.application)).isFalse();
+ }
+
+ @Test
+ public void isIconTintable_noTintableMetadata_shouldReturnFalse() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+ mMetaData.putInt(META_DATA_PREFERENCE_ICON, android.R.drawable.ic_info);
+
+ assertThat(tile.isIconTintable(RuntimeEnvironment.application)).isFalse();
+ }
+
+ @Test
+ public void getPriority_noMetadata_return0() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.getOrder()).isEqualTo(0);
+ }
+
+ @Test
+ public void getPriority_badMetadata_return0() {
+ mMetaData.putString(META_DATA_KEY_ORDER, "1");
+
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.getOrder()).isEqualTo(0);
+ }
+
+ @Test
+ public void getPriority_validMetadata_returnMetadataValue() {
+ mMetaData.putInt(META_DATA_KEY_ORDER, 1);
+
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.getOrder()).isEqualTo(1);
+ }
+
+ @Test
+ @Config(shadows = ShadowTileUtils.class)
+ public void getTitle_shouldEnsureMetadataNotStale() {
+ final ResolveInfo info = new ResolveInfo();
+ info.providerInfo = mProviderInfo;
+ final ShadowPackageManager spm = Shadow.extract(mContext.getPackageManager());
+ spm.addResolveInfoForIntent(
+ new Intent().setClassName(mProviderInfo.packageName, mProviderInfo.name), info);
+ ShadowTileUtils.setMetaData(mMetaData);
+
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+ final long staleTimeStamp = -10000;
+ tile.mLastUpdateTime = staleTimeStamp;
+
+ tile.getTitle(RuntimeEnvironment.application);
+
+ assertThat(tile.mLastUpdateTime).isNotEqualTo(staleTimeStamp);
+ }
+
+ @Implements(TileUtils.class)
+ private static class ShadowTileUtils {
+
+ private static Bundle sMetaData;
+
+ @Implementation
+ protected static Bundle getSwitchDataFromProvider(Context context, String authority,
+ String key) {
+ return sMetaData;
+ }
+
+ private static void setMetaData(Bundle metaData) {
+ sMetaData = metaData;
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
new file mode 100644
index 000000000000..27b3697f54ea
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.drawer;
+
+import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_CHECKED_STATE;
+import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_DATA;
+import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR;
+import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_SUMMARY;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_DYNAMIC_TITLE;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_PROVIDER_ICON;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_GET_SWITCH_DATA;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_IS_CHECKED;
+import static com.android.settingslib.drawer.SwitchesProvider.METHOD_ON_CHECKED_CHANGED;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.os.Bundle;
+
+import com.android.settingslib.drawer.SwitchController.MetaData;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class SwitchesProviderTest {
+
+ @Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ private Context mContext;
+ private ProviderInfo mProviderInfo;
+
+ private TestSwitchesProvider mSwitchesProvider;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mSwitchesProvider = new TestSwitchesProvider();
+ mProviderInfo = new ProviderInfo();
+ mProviderInfo.authority = "auth";
+ }
+
+ @Test
+ public void attachInfo_noController_shouldThrowIllegalArgumentException() {
+ thrown.expect(IllegalArgumentException.class);
+
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_NoSwitchKeyInController_shouldThrowNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ final TestSwitchController controller = new TestSwitchController();
+ mSwitchesProvider.addSwitchController(controller);
+
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_NoMetaDataInController_shouldThrowIllegalArgumentException() {
+ thrown.expect(IllegalArgumentException.class);
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ mSwitchesProvider.addSwitchController(controller);
+
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_duplicateSwitchKey_shouldThrowIllegalArgumentException() {
+ thrown.expect(IllegalArgumentException.class);
+ final TestSwitchController controller1 = new TestSwitchController();
+ final TestSwitchController controller2 = new TestSwitchController();
+ controller1.setKey("123");
+ controller2.setKey("123");
+ controller1.setMetaData(new MetaData("category"));
+ controller2.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller1);
+ mSwitchesProvider.addSwitchController(controller2);
+
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_hasDifferentControllers_shouldNotThrowException() {
+ final TestSwitchController controller1 = new TestSwitchController();
+ final TestSwitchController controller2 = new TestSwitchController();
+ controller1.setKey("123");
+ controller2.setKey("456");
+ controller1.setMetaData(new MetaData("category"));
+ controller2.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller1);
+ mSwitchesProvider.addSwitchController(controller2);
+
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void getSwitchData_shouldReturnDataList() {
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle switchData = mSwitchesProvider.call(METHOD_GET_SWITCH_DATA, "uri" ,
+ null /* extras*/);
+
+ final ArrayList<Bundle> dataList = switchData.getParcelableArrayList(EXTRA_SWITCH_DATA);
+ assertThat(dataList).hasSize(1);
+ assertThat(dataList.get(0).getString(META_DATA_PREFERENCE_KEYHINT)).isEqualTo("123");
+ }
+
+ @Test
+ public void getSwitchDataByKey_shouldReturnData() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle switchData = mSwitchesProvider.call(METHOD_GET_SWITCH_DATA, "uri" , extras);
+
+ assertThat(switchData.getString(META_DATA_PREFERENCE_KEYHINT)).isEqualTo("123");
+ }
+
+ @Test
+ public void isChecked_shouldReturnCheckedState() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ controller.setChecked(true);
+ Bundle result = mSwitchesProvider.call(METHOD_IS_CHECKED, "uri" , extras);
+
+ assertThat(result.getBoolean(EXTRA_SWITCH_CHECKED_STATE)).isTrue();
+
+ controller.setChecked(false);
+ result = mSwitchesProvider.call(METHOD_IS_CHECKED, "uri" , extras);
+
+ assertThat(result.getBoolean(EXTRA_SWITCH_CHECKED_STATE)).isFalse();
+ }
+
+ @Test
+ public void getProviderIcon_noImplementInterface_shouldReturnNull() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle iconBundle = mSwitchesProvider.call(METHOD_GET_PROVIDER_ICON, "uri" , extras);
+
+ assertThat(iconBundle).isNull();
+ }
+
+ @Test
+ public void getProviderIcon_implementInterface_shouldReturnIcon() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestDynamicSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle iconBundle = mSwitchesProvider.call(METHOD_GET_PROVIDER_ICON, "uri" , extras);
+
+ assertThat(iconBundle).isEqualTo(TestDynamicSwitchController.ICON_BUNDLE);
+ }
+
+ @Test
+ public void getDynamicTitle_noImplementInterface_shouldReturnNull() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mSwitchesProvider.call(METHOD_GET_DYNAMIC_TITLE, "uri" , extras);
+
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void getDynamicTitle_implementInterface_shouldReturnTitle() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestDynamicSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mSwitchesProvider.call(METHOD_GET_DYNAMIC_TITLE, "uri" , extras);
+
+ assertThat(result.getString(META_DATA_PREFERENCE_TITLE))
+ .isEqualTo(TestDynamicSwitchController.TITLE);
+ }
+
+ @Test
+ public void getDynamicSummary_noImplementInterface_shouldReturnNull() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mSwitchesProvider.call(METHOD_GET_DYNAMIC_SUMMARY, "uri" , extras);
+
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void getDynamicSummary_implementInterface_shouldReturnSummary() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestDynamicSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mSwitchesProvider.call(METHOD_GET_DYNAMIC_SUMMARY, "uri" , extras);
+
+ assertThat(result.getString(META_DATA_PREFERENCE_SUMMARY))
+ .isEqualTo(TestDynamicSwitchController.SUMMARY);
+ }
+
+ @Test
+ public void onCheckedChangedSuccess_shouldReturnNoError() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mSwitchesProvider.call(METHOD_ON_CHECKED_CHANGED, "uri" , extras);
+
+ assertThat(result.getBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR)).isFalse();
+ }
+
+ @Test
+ public void onCheckedChangedFailed_shouldReturnErrorMessage() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestSwitchController controller = new TestSwitchController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ controller.setErrorMessage("error");
+ mSwitchesProvider.addSwitchController(controller);
+ mSwitchesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mSwitchesProvider.call(METHOD_ON_CHECKED_CHANGED, "uri" , extras);
+
+ assertThat(result.getBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR)).isTrue();
+ assertThat(result.getString(EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE)).isEqualTo("error");
+ }
+
+ private class TestSwitchesProvider extends SwitchesProvider {
+
+ private List<SwitchController> mControllers;
+
+ @Override
+ protected List<SwitchController> createSwitchControllers() {
+ return mControllers;
+ }
+
+ void addSwitchController(SwitchController controller) {
+ if (mControllers == null) {
+ mControllers = new ArrayList<>();
+ }
+ mControllers.add(controller);
+ }
+ }
+
+ private static class TestSwitchController extends SwitchController {
+
+ private String mKey;
+ private MetaData mMetaData;
+ private boolean mChecked;
+ private String mErrorMsg;
+
+ @Override
+ public String getSwitchKey() {
+ return mKey;
+ }
+
+ @Override
+ protected MetaData getMetaData() {
+ return mMetaData;
+ }
+
+ @Override
+ protected boolean isChecked() {
+ return mChecked;
+ }
+
+ @Override
+ protected boolean onCheckedChanged(boolean checked) {
+ return mErrorMsg == null ? true : false;
+ }
+
+ @Override
+ protected String getErrorMessage(boolean attemptedChecked) {
+ return mErrorMsg;
+ }
+
+ void setKey(String key) {
+ mKey = key;
+ }
+
+ void setMetaData(MetaData metaData) {
+ mMetaData = metaData;
+ }
+
+ void setChecked(boolean checked) {
+ mChecked = checked;
+ }
+
+ void setErrorMessage(String errorMsg) {
+ mErrorMsg = errorMsg;
+ }
+ }
+
+ private static class TestDynamicSwitchController extends TestSwitchController
+ implements ProviderIcon, DynamicTitle, DynamicSummary {
+
+ static final String TITLE = "title";
+ static final String SUMMARY = "summary";
+ static final Bundle ICON_BUNDLE = new Bundle();
+
+ @Override
+ public Bundle getProviderIcon() {
+ return ICON_BUNDLE;
+ }
+
+ @Override
+ public String getDynamicTitle() {
+ return TITLE;
+ }
+
+ @Override
+ public String getDynamicSummary() {
+ return SUMMARY;
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index aa1ac4ecd334..b36eb4950b11 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -44,6 +44,7 @@ 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.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Bundle;
@@ -60,12 +61,17 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = TileUtilsTest.ShadowTileUtils.class)
public class TileUtilsTest {
private Context mContext;
@@ -104,12 +110,15 @@ public class TileUtilsTest {
info.add(newInfo(true, testCategory));
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */);
- assertThat(outTiles.size()).isEqualTo(1);
+ assertThat(outTiles).hasSize(2);
assertThat(outTiles.get(0).getCategory()).isEqualTo(testCategory);
+ assertThat(outTiles.get(1).getCategory()).isEqualTo(testCategory);
}
@Test
@@ -123,12 +132,15 @@ public class TileUtilsTest {
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
null /* defaultCategory */, outTiles, false /* requiresSettings */);
- assertThat(outTiles).hasSize(1);
+ assertThat(outTiles).hasSize(2);
assertThat(outTiles.get(0).getKey(mContext)).isEqualTo(keyHint);
+ assertThat(outTiles.get(1).getKey(mContext)).isEqualTo(keyHint);
}
@Test
@@ -141,6 +153,8 @@ public class TileUtilsTest {
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION,
addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */);
@@ -162,6 +176,8 @@ public class TileUtilsTest {
TileUtils.getCategories(mContext, cache);
verify(mPackageManager, atLeastOnce()).queryIntentActivitiesAsUser(
intentCaptor.capture(), anyInt(), anyInt());
+ verify(mPackageManager, atLeastOnce()).queryIntentContentProvidersAsUser(
+ intentCaptor.capture(), anyInt(), anyInt());
assertThat(intentCaptor.getAllValues().get(0).getPackage())
.isEqualTo(TileUtils.SETTING_PKG);
@@ -178,12 +194,15 @@ public class TileUtilsTest {
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */);
- assertThat(outTiles.size()).isEqualTo(1);
+ assertThat(outTiles).hasSize(2);
assertThat(outTiles.get(0).getTitle(mContext)).isEqualTo("my title");
+ assertThat(outTiles.get(1).getTitle(mContext)).isEqualTo("my title");
}
@Test
@@ -197,14 +216,17 @@ public class TileUtilsTest {
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
when(mResources.getString(eq(123)))
.thenReturn("my localized title");
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */);
- assertThat(outTiles.size()).isEqualTo(1);
+ assertThat(outTiles).hasSize(2);
assertThat(outTiles.get(0).getTitle(mContext)).isEqualTo("my localized title");
+ assertThat(outTiles.get(1).getTitle(mContext)).isEqualTo("my localized title");
}
@Test
@@ -220,11 +242,14 @@ public class TileUtilsTest {
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */);
assertThat(outTiles.get(0).isIconTintable(mContext)).isFalse();
+ assertThat(outTiles.get(1).isIconTintable(mContext)).isFalse();
}
@Test
@@ -259,7 +284,6 @@ public class TileUtilsTest {
assertThat(newMetaData).isNotSameAs(oldMetadata);
}
-
@Test
public void getTilesForIntent_shouldMarkIconTintableIfMetadataSet() {
Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
@@ -273,11 +297,14 @@ public class TileUtilsTest {
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */);
assertThat(outTiles.get(0).isIconTintable(mContext)).isTrue();
+ assertThat(outTiles.get(1).isIconTintable(mContext)).isTrue();
}
@Test
@@ -291,11 +318,13 @@ public class TileUtilsTest {
when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
.thenReturn(info);
+ when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(info);
TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */);
- assertThat(outTiles.size()).isEqualTo(1);
+ assertThat(outTiles).hasSize(2);
}
public static ResolveInfo newInfo(boolean systemApp, String category) {
@@ -314,33 +343,66 @@ public class TileUtilsTest {
private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint,
String iconUri, String summaryUri, String title, int titleResId) {
- ResolveInfo info = new ResolveInfo();
+ final Bundle metaData = newMetaData(category, keyHint, iconUri, summaryUri, title,
+ titleResId);
+ final ResolveInfo info = new ResolveInfo();
info.system = systemApp;
+
info.activityInfo = new ActivityInfo();
info.activityInfo.packageName = "abc";
info.activityInfo.name = "123";
- info.activityInfo.metaData = new Bundle();
- info.activityInfo.metaData.putString("com.android.settings.category", category);
- info.activityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, 314159);
- info.activityInfo.metaData.putString(META_DATA_PREFERENCE_SUMMARY, "static-summary");
+ info.activityInfo.metaData = metaData;
+ info.activityInfo.applicationInfo = new ApplicationInfo();
+
+ info.providerInfo = new ProviderInfo();
+ info.providerInfo.packageName = "abc";
+ info.providerInfo.name = "456";
+ info.providerInfo.authority = "auth";
+ ShadowTileUtils.setMetaData(metaData);
+ info.providerInfo.applicationInfo = new ApplicationInfo();
+
+ if (systemApp) {
+ info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ info.providerInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ return info;
+ }
+
+ private static Bundle newMetaData(String category, String keyHint, String iconUri,
+ String summaryUri, String title, int titleResId) {
+ final Bundle metaData = new Bundle();
+ metaData.putString("com.android.settings.category", category);
+ metaData.putInt(META_DATA_PREFERENCE_ICON, 314159);
+ metaData.putString(META_DATA_PREFERENCE_SUMMARY, "static-summary");
if (keyHint != null) {
- info.activityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, keyHint);
+ metaData.putString(META_DATA_PREFERENCE_KEYHINT, keyHint);
}
if (iconUri != null) {
- info.activityInfo.metaData.putString(META_DATA_PREFERENCE_ICON_URI, iconUri);
+ metaData.putString(META_DATA_PREFERENCE_ICON_URI, iconUri);
}
if (summaryUri != null) {
- info.activityInfo.metaData.putString(META_DATA_PREFERENCE_SUMMARY_URI, summaryUri);
+ metaData.putString(META_DATA_PREFERENCE_SUMMARY_URI, summaryUri);
}
if (titleResId != 0) {
- info.activityInfo.metaData.putInt(TileUtils.META_DATA_PREFERENCE_TITLE, titleResId);
+ metaData.putInt(TileUtils.META_DATA_PREFERENCE_TITLE, titleResId);
} else if (title != null) {
- info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
+ metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
}
- info.activityInfo.applicationInfo = new ApplicationInfo();
- if (systemApp) {
- info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ return metaData;
+ }
+
+ @Implements(TileUtils.class)
+ static class ShadowTileUtils {
+
+ private static Bundle sMetaData;
+
+ @Implementation
+ protected static List<Bundle> getSwitchDataFromProvider(Context context, String authority) {
+ return Arrays.asList(sMetaData);
+ }
+
+ private static void setMetaData(Bundle metaData) {
+ sMetaData = metaData;
}
- return info;
}
}