Loading packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java +14 −9 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } } packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * 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; } } packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java 0 → 100644 +256 −0 Original line number Diff line number Diff line /* * 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; } } } packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java 0 → 100644 +186 −0 Original line number Diff line number Diff line /* * 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(); } } packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java +22 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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(); Loading @@ -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; } Loading Loading @@ -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. */ Loading Loading @@ -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. */ Loading Loading @@ -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) { Loading Loading @@ -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) { Loading @@ -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 Loading Loading
packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java +14 −9 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } }
packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * 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; } }
packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java 0 → 100644 +256 −0 Original line number Diff line number Diff line /* * 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; } } }
packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java 0 → 100644 +186 −0 Original line number Diff line number Diff line /* * 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(); } }
packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java +22 −7 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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(); Loading @@ -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; } Loading Loading @@ -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. */ Loading Loading @@ -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. */ Loading Loading @@ -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) { Loading Loading @@ -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) { Loading @@ -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 Loading