[SettingsLib] Support pure switch of inline toggle of Settings Injection v2
Bug: 132808482 Test: robotest Change-Id: I2e76bb1f11b2556ea10a45a920530a7f93c6506d
This commit is contained in:
@@ -52,15 +52,6 @@ public class ActivityTile extends Tile {
|
||||
return getPackageName() + "/" + getComponentName();
|
||||
}
|
||||
|
||||
@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) {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -163,6 +172,13 @@ public abstract class Tile implements Parcelable {
|
||||
&& mMetaData.get(META_DATA_KEY_ORDER) instanceof Integer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -188,6 +190,17 @@ public class TileUtils {
|
||||
public static final String META_DATA_PREFERENCE_SUMMARY_URI =
|
||||
"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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
if (keyHint != null) {
|
||||
info.activityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, keyHint);
|
||||
}
|
||||
if (iconUri != null) {
|
||||
info.activityInfo.metaData.putString(META_DATA_PREFERENCE_ICON_URI, iconUri);
|
||||
}
|
||||
if (summaryUri != null) {
|
||||
info.activityInfo.metaData.putString(META_DATA_PREFERENCE_SUMMARY_URI, summaryUri);
|
||||
}
|
||||
if (titleResId != 0) {
|
||||
info.activityInfo.metaData.putInt(TileUtils.META_DATA_PREFERENCE_TITLE, titleResId);
|
||||
} else if (title != null) {
|
||||
info.activityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
|
||||
}
|
||||
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) {
|
||||
metaData.putString(META_DATA_PREFERENCE_KEYHINT, keyHint);
|
||||
}
|
||||
if (iconUri != null) {
|
||||
metaData.putString(META_DATA_PREFERENCE_ICON_URI, iconUri);
|
||||
}
|
||||
if (summaryUri != null) {
|
||||
metaData.putString(META_DATA_PREFERENCE_SUMMARY_URI, summaryUri);
|
||||
}
|
||||
if (titleResId != 0) {
|
||||
metaData.putInt(TileUtils.META_DATA_PREFERENCE_TITLE, titleResId);
|
||||
} else if (title != null) {
|
||||
metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user