Merge "Refactor and fix flaky tests in WindowOnBackInvokedDispatcherTest" into udc-dev am: f4f331d65a am: ba85d52709
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23352458
Change-Id: I5d732c663081c0a19d1b48c70839ca3ace905f02
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index e908ced..48b5cac 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -212,14 +212,7 @@
@GuardedBy("mLock")
private boolean mFoldedDeviceState;
- private final CameraManager.DeviceStateListener mFoldStateListener =
- new CameraManager.DeviceStateListener() {
- @Override
- public final void onDeviceStateChanged(boolean folded) {
- synchronized (mLock) {
- mFoldedDeviceState = folded;
- }
- }};
+ private CameraManager.DeviceStateListener mFoldStateListener;
private static final String TAG = "CameraCharacteristics";
@@ -245,7 +238,18 @@
/**
* Return the device state listener for this Camera characteristics instance
*/
- CameraManager.DeviceStateListener getDeviceStateListener() { return mFoldStateListener; }
+ CameraManager.DeviceStateListener getDeviceStateListener() {
+ if (mFoldStateListener == null) {
+ mFoldStateListener = new CameraManager.DeviceStateListener() {
+ @Override
+ public final void onDeviceStateChanged(boolean folded) {
+ synchronized (mLock) {
+ mFoldedDeviceState = folded;
+ }
+ }};
+ }
+ return mFoldStateListener;
+ }
/**
* Overrides the property value
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 51501b5..85f8ca6 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1836,6 +1836,7 @@
ctx.getSystemService(DeviceStateManager.class).registerCallback(
new HandlerExecutor(mDeviceStateHandler), mFoldStateListener);
} catch (IllegalStateException e) {
+ mFoldStateListener = null;
Log.v(TAG, "Failed to register device state listener!");
Log.v(TAG, "Device state dependent characteristics updates will not be" +
"functional!");
diff --git a/core/res/res/layout/shutdown_dialog.xml b/core/res/res/layout/shutdown_dialog.xml
index ec67aa8..726c255 100644
--- a/core/res/res/layout/shutdown_dialog.xml
+++ b/core/res/res/layout/shutdown_dialog.xml
@@ -40,7 +40,7 @@
android:fontFamily="@string/config_headlineFontFamily"/>
<TextView
- android:id="@+id/text2"
+ android:id="@id/text2"
android:layout_width="wrap_content"
android:layout_height="32sp"
android:text="@string/shutdown_progress"
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index fd74185..8420934 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -167,9 +167,4 @@
true, routing from the android emergency number database will be ignored. -->
<bool name="ignore_emergency_number_routing_from_db">false</bool>
<java-symbol type="bool" name="ignore_emergency_number_routing_from_db" />
-
- <!-- Whether "Virtual DSDA", i.e. in-call IMS connectivity can be provided on both subs with
- only single logical modem, by using its data connection in addition to cellular IMS. -->
- <bool name="config_enable_virtual_dsda">false</bool>
- <java-symbol type="bool" name="config_enable_virtual_dsda" />
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index af2b3cf..8e34412 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5022,6 +5022,7 @@
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />
<java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />
+
<java-symbol name="materialColorOnSecondaryFixedVariant" type="attr"/>
<java-symbol name="materialColorOnTertiaryFixedVariant" type="attr"/>
<java-symbol name="materialColorSurfaceContainerLowest" type="attr"/>
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicSummary.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicSummary.java
index c9d9b57..5b7899b 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicSummary.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicSummary.java
@@ -16,7 +16,7 @@
package com.android.settingslib.drawer;
-/** Interface for {@link SwitchController} whose instances support dynamic summary */
+/** Interface for {@link EntryController} whose instances support dynamic summary */
public interface DynamicSummary {
/** @return the dynamic summary text */
String getDynamicSummary();
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicTitle.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicTitle.java
index af711dd..cb15773 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicTitle.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/DynamicTitle.java
@@ -16,7 +16,7 @@
package com.android.settingslib.drawer;
-/** Interface for {@link SwitchController} whose instances support dynamic title */
+/** Interface for {@link EntryController} whose instances support dynamic title */
public interface DynamicTitle {
/** @return the dynamic title text */
String getDynamicTitle();
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/EntriesProvider.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/EntriesProvider.java
new file mode 100644
index 0000000..1c14c0a
--- /dev/null
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/EntriesProvider.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2023 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 entries to Settings.
+ */
+public abstract class EntriesProvider extends ContentProvider {
+ private static final String TAG = "EntriesProvider";
+
+ public static final String METHOD_GET_ENTRY_DATA = "getEntryData";
+ 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";
+
+ /**
+ * @deprecated use {@link #METHOD_GET_ENTRY_DATA} instead.
+ */
+ @Deprecated
+ public static final String METHOD_GET_SWITCH_DATA = "getSwitchData";
+
+ public static final String EXTRA_ENTRY_DATA = "entry_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";
+
+ /**
+ * @deprecated use {@link #EXTRA_ENTRY_DATA} instead.
+ */
+ @Deprecated
+ public static final String EXTRA_SWITCH_DATA = "switch_data";
+
+ private String mAuthority;
+ private final Map<String, EntryController> mControllerMap = new LinkedHashMap<>();
+ private final List<Bundle> mEntryDataList = new ArrayList<>();
+
+ /**
+ * Get a list of {@link EntryController} for this provider.
+ */
+ protected abstract List<? extends EntryController> createEntryControllers();
+
+ protected EntryController getController(String key) {
+ return mControllerMap.get(key);
+ }
+
+ @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<? extends EntryController> controllers = createEntryControllers();
+ if (controllers == null || controllers.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+
+ for (EntryController controller : controllers) {
+ final String key = controller.getKey();
+ if (TextUtils.isEmpty(key)) {
+ throw new NullPointerException("Entry key cannot be null: "
+ + controller.getClass().getSimpleName());
+ } else if (mControllerMap.containsKey(key)) {
+ throw new IllegalArgumentException("Entry key " + key + " is duplicated by: "
+ + controller.getClass().getSimpleName());
+ }
+
+ controller.setAuthority(mAuthority);
+ mControllerMap.put(key, controller);
+ if (!(controller instanceof PrimarySwitchController)) {
+ mEntryDataList.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)) {
+ switch (method) {
+ case METHOD_GET_ENTRY_DATA:
+ bundle.putParcelableList(EXTRA_ENTRY_DATA, mEntryDataList);
+ return bundle;
+ case METHOD_GET_SWITCH_DATA:
+ bundle.putParcelableList(EXTRA_SWITCH_DATA, mEntryDataList);
+ return bundle;
+ default:
+ return null;
+ }
+ }
+
+ final EntryController controller = mControllerMap.get(key);
+ if (controller == null) {
+ return null;
+ }
+
+ switch (method) {
+ case METHOD_GET_ENTRY_DATA:
+ case METHOD_GET_SWITCH_DATA:
+ if (!(controller instanceof PrimarySwitchController)) {
+ return controller.getBundle();
+ }
+ break;
+ 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:
+ if (controller instanceof ProviderSwitch) {
+ bundle.putBoolean(EXTRA_SWITCH_CHECKED_STATE,
+ ((ProviderSwitch) controller).isSwitchChecked());
+ return bundle;
+ }
+ break;
+ case METHOD_ON_CHECKED_CHANGED:
+ if (controller instanceof ProviderSwitch) {
+ return onSwitchCheckedChanged(extras.getBoolean(EXTRA_SWITCH_CHECKED_STATE),
+ (ProviderSwitch) controller);
+ }
+ break;
+ }
+ return null;
+ }
+
+ private Bundle onSwitchCheckedChanged(boolean checked, ProviderSwitch controller) {
+ final boolean success = controller.onSwitchCheckedChanged(checked);
+ final Bundle bundle = new Bundle();
+ bundle.putBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR, !success);
+ if (success) {
+ if (controller instanceof DynamicSummary) {
+ ((EntryController) controller).notifySummaryChanged(getContext());
+ }
+ } else {
+ bundle.putString(EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE,
+ controller.getSwitchErrorMessage(checked));
+ }
+ return bundle;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+}
+
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/EntryController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/EntryController.java
new file mode 100644
index 0000000..5d6e6a3
--- /dev/null
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/EntryController.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2023 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.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_PENDING_INTENT;
+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.app.PendingIntent;
+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 EntryController {
+
+ private String mAuthority;
+
+ /**
+ * Returns the key for this switch.
+ */
+ public abstract String getKey();
+
+ /**
+ * Returns the {@link MetaData} for this switch.
+ */
+ protected abstract MetaData getMetaData();
+
+ /**
+ * 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);
+ }
+ }
+
+ void setAuthority(String authority) {
+ mAuthority = authority;
+ }
+
+ Bundle getBundle() {
+ final MetaData metaData = getMetaData();
+ if (metaData == null) {
+ throw new NullPointerException("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, getKey());
+ 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);
+ }
+ if (this instanceof ProviderSwitch) {
+ bundle.putString(META_DATA_PREFERENCE_SWITCH_URI, uriString);
+ }
+ return bundle;
+ }
+
+ private void notifyChanged(Context context, String method) {
+ final Uri uri = TileUtils.buildUri(mAuthority, method, getKey());
+ 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;
+ private PendingIntent mPendingIntent;
+
+ /**
+ * @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;
+ }
+
+ public MetaData setPendingIntent(PendingIntent pendingIntent) {
+ mPendingIntent = pendingIntent;
+ return this;
+ }
+
+ protected 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);
+ }
+
+ if (mPendingIntent != null) {
+ bundle.putParcelable(META_DATA_PREFERENCE_PENDING_INTENT, mPendingIntent);
+ }
+
+ return bundle;
+ }
+ }
+}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderIcon.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderIcon.java
index 2945d5c1..3aa6fcb 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderIcon.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderIcon.java
@@ -19,7 +19,7 @@
import android.os.Bundle;
/**
- * Interface for {@link SwitchController} whose instances support icon provided from the content
+ * Interface for {@link EntryController} whose instances support icon provided from the content
* provider
*/
public interface ProviderIcon {
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderSwitch.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderSwitch.java
new file mode 100644
index 0000000..47eb31c
--- /dev/null
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderSwitch.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 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;
+
+/**
+ * Interface for {@link EntryController} whose instances support switch widget provided from the
+ * content provider
+ */
+public interface ProviderSwitch {
+ /**
+ * Returns the checked state of this switch.
+ */
+ boolean isSwitchChecked();
+
+ /**
+ * Called when the checked state of this switch is changed.
+ *
+ * @return true if the checked state was successfully changed, otherwise false
+ */
+ boolean onSwitchCheckedChanged(boolean checked);
+
+ /**
+ * Returns the error message which will be toasted when {@link #onSwitchCheckedChanged} returns
+ * false.
+ */
+ String getSwitchErrorMessage(boolean attemptedChecked);
+}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
index 54da585..b775e93 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java
@@ -75,7 +75,7 @@
if (infoList != null && !infoList.isEmpty()) {
final ProviderInfo providerInfo = infoList.get(0).providerInfo;
mComponentInfo = providerInfo;
- setMetaData(TileUtils.getSwitchDataFromProvider(context, providerInfo.authority,
+ setMetaData(TileUtils.getEntryDataFromProvider(context, providerInfo.authority,
mKey));
} else {
Log.e(TAG, "Cannot find package info for "
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java
index 23669b2..a1a4e58 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java
@@ -16,38 +16,16 @@
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.
+ *
+ * @deprecated Use {@link EntriesProvider} with {@link ProviderSwitch} instead.
*/
-public abstract class SwitchController {
+@Deprecated
+public abstract class SwitchController extends EntryController implements ProviderSwitch {
- private String mAuthority;
/**
* Returns the key for this switch.
@@ -55,11 +33,6 @@
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();
@@ -76,181 +49,41 @@
*/
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);
- }
+ @Override
+ public String getKey() {
+ return getSwitchKey();
+ }
+
+ @Override
+ public boolean isSwitchChecked() {
+ return isChecked();
+ }
+
+ @Override
+ public boolean onSwitchCheckedChanged(boolean checked) {
+ return onCheckedChanged(checked);
+ }
+
+ @Override
+ public String getSwitchErrorMessage(boolean attemptedChecked) {
+ return getErrorMessage(attemptedChecked);
}
/**
- * Notify registered observers that summary was updated and attempt to sync changes.
+ * Same as {@link EntryController.MetaData}, for backwards compatibility purpose.
+ *
+ * @deprecated Use {@link EntryController.MetaData} instead.
*/
- 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 NullPointerException("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;
-
+ @Deprecated
+ protected static class MetaData extends EntryController.MetaData {
/**
* @param category the category of the switch. This value must be from {@link CategoryKey}.
+ *
+ * @deprecated Use {@link EntryController.MetaData} instead.
*/
+ @Deprecated
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;
+ super(category);
}
}
}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
index f2b3e30..ad00ced 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
@@ -16,46 +16,15 @@
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.
+ *
+ * @deprecated Use {@link EntriesProvider} instead.
*/
-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> mSwitchDataList = new ArrayList<>();
+@Deprecated
+public abstract class SwitchesProvider extends EntriesProvider {
/**
* Get a list of {@link SwitchController} for this provider.
@@ -63,129 +32,7 @@
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);
- if (!(controller instanceof PrimarySwitchController)) {
- mSwitchDataList.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, mSwitchDataList);
- return bundle;
- }
- return null;
- }
-
- final SwitchController controller = mControllerMap.get(key);
- if (controller == null) {
- return null;
- }
-
- switch (method) {
- case METHOD_GET_SWITCH_DATA:
- if (!(controller instanceof PrimarySwitchController)) {
- return controller.getBundle();
- }
- break;
- 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();
+ protected List<? extends EntryController> createEntryControllers() {
+ return createSwitchControllers();
}
}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index a0c8ac4..00dd8cc 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -19,6 +19,7 @@
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_NEW_TASK;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_GROUP_KEY;
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;
@@ -29,6 +30,7 @@
import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ComponentInfo;
@@ -47,6 +49,7 @@
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
/**
* Description of a single dashboard tile that the user can select.
@@ -60,6 +63,8 @@
*/
public ArrayList<UserHandle> userHandle = new ArrayList<>();
+ public HashMap<UserHandle, PendingIntent> pendingIntentMap = new HashMap<>();
+
@VisibleForTesting
long mLastUpdateTime;
private final String mComponentPackage;
@@ -186,6 +191,13 @@
}
/**
+ * Check whether tile has a pending intent.
+ */
+ public boolean hasPendingIntent() {
+ return !pendingIntentMap.isEmpty();
+ }
+
+ /**
* Title of the tile that is shown to the user.
*/
public CharSequence getTitle(Context context) {
@@ -395,6 +407,76 @@
return TextUtils.equals(profile, PROFILE_PRIMARY);
}
+ /**
+ * Returns whether the tile belongs to another group / category.
+ */
+ public boolean hasGroupKey() {
+ return mMetaData != null
+ && !TextUtils.isEmpty(mMetaData.getString(META_DATA_PREFERENCE_GROUP_KEY));
+ }
+
+ /**
+ * Returns the group / category key this tile belongs to.
+ */
+ public String getGroupKey() {
+ return (mMetaData == null) ? null : mMetaData.getString(META_DATA_PREFERENCE_GROUP_KEY);
+ }
+
+ /**
+ * The type of the tile.
+ */
+ public enum Type {
+ /**
+ * A preference that can be tapped on to open a new page.
+ */
+ ACTION,
+
+ /**
+ * A preference that can be tapped on to open an external app.
+ */
+ EXTERNAL_ACTION,
+
+ /**
+ * A preference that shows an on / off switch that can be toggled by the user.
+ */
+ SWITCH,
+
+ /**
+ * A preference with both an on / off switch, and a tappable area that can perform an
+ * action.
+ */
+ SWITCH_WITH_ACTION,
+
+ /**
+ * A preference category with a title that can be used to group multiple preferences
+ * together.
+ */
+ GROUP;
+ }
+
+ /**
+ * Returns the type of the tile.
+ *
+ * @see Type
+ */
+ public Type getType() {
+ boolean hasExternalAction = hasPendingIntent();
+ boolean hasAction = hasExternalAction || this instanceof ActivityTile;
+ boolean hasSwitch = hasSwitch();
+
+ if (hasSwitch && hasAction) {
+ return Type.SWITCH_WITH_ACTION;
+ } else if (hasSwitch) {
+ return Type.SWITCH;
+ } else if (hasExternalAction) {
+ return Type.EXTERNAL_ACTION;
+ } else if (hasAction) {
+ return Type.ACTION;
+ } else {
+ return Type.GROUP;
+ }
+ }
+
public static final Comparator<Tile> TILE_COMPARATOR =
(lhs, rhs) -> rhs.getOrder() - lhs.getOrder();
}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index acc0087..e46db75 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -113,6 +113,12 @@
public static final String META_DATA_PREFERENCE_KEYHINT = "com.android.settings.keyhint";
/**
+ * Name of the meta-data item that can be set in the AndroidManifest.xml or in the content
+ * provider to specify the key of a group / category where this preference belongs to.
+ */
+ public static final String META_DATA_PREFERENCE_GROUP_KEY = "com.android.settings.group_key";
+
+ /**
* Order of the item that should be displayed on screen. Bigger value items displays closer on
* top.
*/
@@ -202,6 +208,13 @@
"com.android.settings.switch_uri";
/**
+ * Name of the meta-data item that can be set from the content provider providing the intent
+ * that will be executed when the user taps on the preference.
+ */
+ public static final String META_DATA_PREFERENCE_PENDING_INTENT =
+ "com.android.settings.pending_intent";
+
+ /**
* Value for {@link #META_DATA_KEY_PROFILE}. When the device has a managed profile,
* the app will always be run in the primary profile.
*
@@ -331,12 +344,12 @@
continue;
}
final ProviderInfo providerInfo = resolved.providerInfo;
- final List<Bundle> switchData = getSwitchDataFromProvider(context,
+ final List<Bundle> entryData = getEntryDataFromProvider(context,
providerInfo.authority);
- if (switchData == null || switchData.isEmpty()) {
+ if (entryData == null || entryData.isEmpty()) {
continue;
}
- for (Bundle metaData : switchData) {
+ for (Bundle metaData : entryData) {
loadTile(user, addedCache, defaultCategory, outTiles, intent, metaData,
providerInfo);
}
@@ -386,27 +399,43 @@
if (!tile.userHandle.contains(user)) {
tile.userHandle.add(user);
}
+ if (metaData.containsKey(META_DATA_PREFERENCE_PENDING_INTENT)) {
+ tile.pendingIntentMap.put(
+ user, metaData.getParcelable(META_DATA_PREFERENCE_PENDING_INTENT));
+ }
if (!outTiles.contains(tile)) {
outTiles.add(tile);
}
}
- /** Returns the switch data of the key specified from the provider */
+ /** Returns the entry 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) {
+ static Bundle getEntryDataFromProvider(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 */);
+ final Uri uri = buildUri(authority, EntriesProvider.METHOD_GET_ENTRY_DATA, key);
+ Bundle result = getBundleFromUri(context, uri, providerMap, null /* bundle */);
+ if (result == null) {
+ Uri fallbackUri = buildUri(authority, EntriesProvider.METHOD_GET_SWITCH_DATA, key);
+ result = getBundleFromUri(context, fallbackUri, providerMap, null /* bundle */);
+ }
+ return result;
}
- /** Returns all switch data from the provider */
- private static List<Bundle> getSwitchDataFromProvider(Context context, String authority) {
+ /** Returns all entry data from the provider */
+ private static List<Bundle> getEntryDataFromProvider(Context context, String authority) {
final Map<String, IContentProvider> providerMap = new ArrayMap<>();
- final Uri uri = buildUri(authority, SwitchesProvider.METHOD_GET_SWITCH_DATA);
+ final Uri uri = buildUri(authority, EntriesProvider.METHOD_GET_ENTRY_DATA);
final Bundle result = getBundleFromUri(context, uri, providerMap, null /* bundle */);
- return result != null
- ? result.getParcelableArrayList(SwitchesProvider.EXTRA_SWITCH_DATA)
- : null;
+ if (result != null) {
+ return result.getParcelableArrayList(EntriesProvider.EXTRA_ENTRY_DATA);
+ } else {
+ Uri fallbackUri = buildUri(authority, EntriesProvider.METHOD_GET_SWITCH_DATA);
+ Bundle fallbackResult =
+ getBundleFromUri(context, fallbackUri, providerMap, null /* bundle */);
+ return fallbackResult != null
+ ? fallbackResult.getParcelableArrayList(EntriesProvider.EXTRA_SWITCH_DATA)
+ : null;
+ }
}
/**
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 058065e..bac6306 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -519,12 +519,9 @@
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Daugiau laiko."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mažiau laiko."</string>
<string name="cancel" msgid="5665114069455378395">"Atšaukti"</string>
- <!-- no translation found for next (2699398661093607009) -->
- <skip />
- <!-- no translation found for back (5554327870352703710) -->
- <skip />
- <!-- no translation found for save (3745809743277153149) -->
- <skip />
+ <string name="next" msgid="2699398661093607009">"Kitas"</string>
+ <string name="back" msgid="5554327870352703710">"Atgal"</string>
+ <string name="save" msgid="3745809743277153149">"Išsaugoti"</string>
<string name="okay" msgid="949938843324579502">"Gerai"</string>
<string name="done" msgid="381184316122520313">"Atlikta"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signalai ir priminimai"</string>
@@ -579,12 +576,9 @@
<string name="user_add_user_title" msgid="5457079143694924885">"Pridėti naują naudotoją?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"Galite bendrinti šį įrenginį su kitais žmonėmis sukūrę papildomų naudotojų. Kiekvienam naudotojui suteikiama atskira erdvė, kurią jie gali tinkinti naudodami programas, ekrano foną ir kt. Be to, naudotojai gali koreguoti įrenginio nustatymus, pvz., „Wi‑Fi“, kurie taikomi visiems.\n\nKai pridedate naują naudotoją, šis asmuo turi nusistatyti savo erdvę.\n\nBet kuris naudotojas gali atnaujinti visų kitų naudotojų programas. Pasiekiamumo nustatymai ir paslaugos gali nebūti perkeltos naujam naudotojui."</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo vietą.\n\nBet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string>
- <!-- no translation found for user_grant_admin_title (5157031020083343984) -->
- <skip />
- <!-- no translation found for user_grant_admin_message (1673791931033486709) -->
- <skip />
- <!-- no translation found for user_grant_admin_button (5441486731331725756) -->
- <skip />
+ <string name="user_grant_admin_title" msgid="5157031020083343984">"Nustatyti šį naudotoją kaip administratorių?"</string>
+ <string name="user_grant_admin_message" msgid="1673791931033486709">"Administratoriai turi specialių privilegijų, kurių kiti naudotojai neturi. Administratorius gali tvarkyti visus naudotojus, atnaujinti ar iš naujo nustatyti šį įrenginį, keisti nustatymus, peržiūrėti visas įdiegtas programas ir suteikti administratoriaus privilegijas kitiems naudotojams arba jas panaikinti."</string>
+ <string name="user_grant_admin_button" msgid="5441486731331725756">"Nustatyti kaip administratorių"</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Nustatyti naudotoją dabar?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Įsitikinkite, kad asmuo gali paimti įrenginį ir nustatyti savo vietą"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Nustatyti profilį dabar?"</string>
@@ -616,10 +610,8 @@
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Bus pradėta nauja svečio sesija ir iš esamos sesijos bus ištrintos visos programos ir duomenys"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Išeiti iš svečio režimo?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Bus ištrintos esamos svečio sesijos programos ir duomenys"</string>
- <!-- no translation found for grant_admin (4323199171790522574) -->
- <skip />
- <!-- no translation found for not_grant_admin (3557849576157702485) -->
- <skip />
+ <string name="grant_admin" msgid="4323199171790522574">"Taip, nustatyti kaip administratorių"</string>
+ <string name="not_grant_admin" msgid="3557849576157702485">"Ne, nenustatyti kaip administratoriaus"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Išeiti"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Išsaugoti svečio veiklą?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Galite išsaugoti esamos sesijos veiklą arba ištrinti visas programas ir duomenis"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 7cf8968..052840d 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -519,12 +519,9 @@
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"增加时间。"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"减少时间。"</string>
<string name="cancel" msgid="5665114069455378395">"取消"</string>
- <!-- no translation found for next (2699398661093607009) -->
- <skip />
- <!-- no translation found for back (5554327870352703710) -->
- <skip />
- <!-- no translation found for save (3745809743277153149) -->
- <skip />
+ <string name="next" msgid="2699398661093607009">"继续"</string>
+ <string name="back" msgid="5554327870352703710">"返回"</string>
+ <string name="save" msgid="3745809743277153149">"保存"</string>
<string name="okay" msgid="949938843324579502">"确定"</string>
<string name="done" msgid="381184316122520313">"完成"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"闹钟和提醒"</string>
@@ -579,12 +576,9 @@
<string name="user_add_user_title" msgid="5457079143694924885">"要添加新用户吗?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"创建新用户后,您就能够与其他人共用此设备。每位用户都有自己的专属空间,而且在自己的个人空间内还可以自行安装自己想要的应用、设置壁纸等。此外,用户还可以调整会影响所有用户的设备设置(例如 WLAN 设置)。\n\n当您添加新用户后,该用户需要自行设置个人空间。\n\n任何用户都可以为所有其他用户更新应用。无障碍功能设置和服务可能无法转移给新用户。"</string>
<string name="user_add_user_message_short" msgid="3295959985795716166">"当您添加新用户后,该用户需要自行设置个人空间。\n\n任何用户都可以为所有其他用户更新应用。"</string>
- <!-- no translation found for user_grant_admin_title (5157031020083343984) -->
- <skip />
- <!-- no translation found for user_grant_admin_message (1673791931033486709) -->
- <skip />
- <!-- no translation found for user_grant_admin_button (5441486731331725756) -->
- <skip />
+ <string name="user_grant_admin_title" msgid="5157031020083343984">"将此用户设为管理员?"</string>
+ <string name="user_grant_admin_message" msgid="1673791931033486709">"管理员拥有其他用户没有的特殊权限。管理员可以管理所有用户、更新或重置此设备、修改设置、查看所有已安装的应用,以及授予或撤消其他用户的管理员权限。"</string>
+ <string name="user_grant_admin_button" msgid="5441486731331725756">"设为管理员"</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"要现在设置该用户吗?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"请让相应用户操作设备并设置他们自己的空间。"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"要立即设置个人资料吗?"</string>
@@ -616,10 +610,8 @@
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"此操作会开始新的访客会话,并删除当前会话中的所有应用和数据"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"要退出访客模式吗?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"此操作会删除当前访客会话中的所有应用和数据"</string>
- <!-- no translation found for grant_admin (4323199171790522574) -->
- <skip />
- <!-- no translation found for not_grant_admin (3557849576157702485) -->
- <skip />
+ <string name="grant_admin" msgid="4323199171790522574">"是,将其设为管理员"</string>
+ <string name="not_grant_admin" msgid="3557849576157702485">"不,不要将其设为管理员"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"退出"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"要保存访客活动记录吗?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"您可以保存当前会话中的活动记录,也可以删除所有应用和数据"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 09abc39..9ee8a32 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -209,8 +209,7 @@
}
final ComponentName cn = intent.getComponent();
final String key = cn != null ? cn.flattenToString() : intent.getAction();
- return logSettingsTileClick(key + (isWorkProfile ? "/work" : "/personal"),
- sourceMetricsCategory);
+ return logSettingsTileClickWithProfile(key, sourceMetricsCategory, isWorkProfile);
}
/**
@@ -226,4 +225,20 @@
clicked(sourceMetricsCategory, logKey);
return true;
}
+
+ /**
+ * Logs an event when the setting key is clicked with a specific profile from Profile select
+ * dialog.
+ *
+ * @return true if the key is loggable, otherwise false
+ */
+ public boolean logSettingsTileClickWithProfile(String logKey, int sourceMetricsCategory,
+ boolean isWorkProfile) {
+ if (TextUtils.isEmpty(logKey)) {
+ // Not loggable
+ return false;
+ }
+ clicked(sourceMetricsCategory, logKey + (isWorkProfile ? "/work" : "/personal"));
+ return true;
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index 3352d86..dd8d54a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -203,4 +203,24 @@
assertThat(loggable).isFalse();
verifyNoMoreInteractions(mLogWriter);
}
+
+ @Test
+ public void logSettingsTileClickWithProfile_isPersonalProfile_shouldTagPersonal() {
+ final String key = "abc";
+ final boolean loggable = mProvider.logSettingsTileClickWithProfile(key,
+ MetricsEvent.SETTINGS_GESTURES, false);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).clicked(MetricsEvent.SETTINGS_GESTURES, "abc/personal");
+ }
+
+ @Test
+ public void logSettingsTileClickWithProfile_isWorkProfile_shouldTagWork() {
+ final String key = "abc";
+ final boolean loggable = mProvider.logSettingsTileClickWithProfile(key,
+ MetricsEvent.SETTINGS_GESTURES, true);
+
+ assertThat(loggable).isTrue();
+ verify(mLogWriter).clicked(MetricsEvent.SETTINGS_GESTURES, "abc/work");
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
index aa6b0bf..4d2b1ae 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
@@ -17,19 +17,23 @@
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_GROUP_KEY;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
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.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
+import android.os.UserHandle;
import org.junit.Before;
import org.junit.Test;
@@ -191,4 +195,65 @@
assertThat(tile.getTitle(RuntimeEnvironment.application)).isNull();
}
+
+ @Test
+ public void hasPendingIntent_empty_returnsFalse() {
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.hasPendingIntent()).isFalse();
+ }
+
+ @Test
+ public void hasPendingIntent_notEmpty_returnsTrue() {
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+ tile.pendingIntentMap.put(
+ UserHandle.CURRENT, PendingIntent.getActivity(mContext, 0, new Intent(), 0));
+
+ assertThat(tile.hasPendingIntent()).isTrue();
+ }
+
+ @Test
+ public void hasGroupKey_empty_returnsFalse() {
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.hasGroupKey()).isFalse();
+ }
+
+ @Test
+ public void hasGroupKey_notEmpty_returnsTrue() {
+ mActivityInfo.metaData.putString(META_DATA_PREFERENCE_GROUP_KEY, "test_key");
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.hasGroupKey()).isTrue();
+ }
+
+ @Test
+ public void getGroupKey_empty_returnsNull() {
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.getGroupKey()).isNull();
+ }
+
+ @Test
+ public void getGroupKey_notEmpty_returnsValue() {
+ mActivityInfo.metaData.putString(META_DATA_PREFERENCE_GROUP_KEY, "test_key");
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.getGroupKey()).isEqualTo("test_key");
+ }
+
+ @Test
+ public void getType_withoutSwitch_returnsAction() {
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.getType()).isEqualTo(Tile.Type.ACTION);
+ }
+
+ @Test
+ public void getType_withSwitch_returnsSwitchWithAction() {
+ mActivityInfo.metaData.putString(META_DATA_PREFERENCE_SWITCH_URI, "test://testabc/");
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.getType()).isEqualTo(Tile.Type.SWITCH_WITH_ACTION);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/EntriesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/EntriesProviderTest.java
new file mode 100644
index 0000000..a248330
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/EntriesProviderTest.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2023 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.EntriesProvider.EXTRA_ENTRY_DATA;
+import static com.android.settingslib.drawer.EntriesProvider.EXTRA_SWITCH_CHECKED_STATE;
+import static com.android.settingslib.drawer.EntriesProvider.EXTRA_SWITCH_DATA;
+import static com.android.settingslib.drawer.EntriesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR;
+import static com.android.settingslib.drawer.EntriesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR_MESSAGE;
+import static com.android.settingslib.drawer.EntriesProvider.METHOD_GET_DYNAMIC_SUMMARY;
+import static com.android.settingslib.drawer.EntriesProvider.METHOD_GET_DYNAMIC_TITLE;
+import static com.android.settingslib.drawer.EntriesProvider.METHOD_GET_ENTRY_DATA;
+import static com.android.settingslib.drawer.EntriesProvider.METHOD_GET_PROVIDER_ICON;
+import static com.android.settingslib.drawer.EntriesProvider.METHOD_GET_SWITCH_DATA;
+import static com.android.settingslib.drawer.EntriesProvider.METHOD_IS_CHECKED;
+import static com.android.settingslib.drawer.EntriesProvider.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_PENDING_INTENT;
+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.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ProviderInfo;
+import android.os.Bundle;
+
+import com.android.settingslib.drawer.EntryController.MetaData;
+import com.android.settingslib.drawer.PrimarySwitchControllerTest.TestPrimarySwitchController;
+
+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 EntriesProviderTest {
+
+ @Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
+ private Context mContext;
+ private ProviderInfo mProviderInfo;
+
+ private TestEntriesProvider mEntriesProvider;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mEntriesProvider = new TestEntriesProvider();
+ mProviderInfo = new ProviderInfo();
+ mProviderInfo.authority = "auth";
+ }
+
+ @Test
+ public void attachInfo_noController_shouldThrowIllegalArgumentException() {
+ thrown.expect(IllegalArgumentException.class);
+
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_NoKeyInController_shouldThrowNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ final TestEntryController controller = new TestEntryController();
+ mEntriesProvider.addController(controller);
+
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_NoMetaDataInController_shouldThrowNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ final TestEntryController controller = new TestEntryController();
+ controller.setKey("123");
+ mEntriesProvider.addController(controller);
+
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_duplicateKey_shouldThrowIllegalArgumentException() {
+ thrown.expect(IllegalArgumentException.class);
+ final TestEntryController controller1 = new TestEntryController();
+ final TestEntryController controller2 = new TestEntryController();
+ controller1.setKey("123");
+ controller2.setKey("123");
+ controller1.setMetaData(new MetaData("category"));
+ controller2.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller1);
+ mEntriesProvider.addController(controller2);
+
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void attachInfo_hasDifferentControllers_shouldNotThrowException() {
+ final TestEntryController controller1 = new TestEntryController();
+ final TestEntryController controller2 = new TestEntryController();
+ controller1.setKey("123");
+ controller2.setKey("456");
+ controller1.setMetaData(new MetaData("category"));
+ controller2.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller1);
+ mEntriesProvider.addController(controller2);
+
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+ }
+
+ @Test
+ public void getEntryData_shouldNotReturnPrimarySwitchData() {
+ final EntryController controller = new TestPrimarySwitchController("123");
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle switchData = mEntriesProvider.call(METHOD_GET_ENTRY_DATA, "uri",
+ null /* extras*/);
+
+ final ArrayList<Bundle> dataList = switchData.getParcelableArrayList(EXTRA_ENTRY_DATA);
+ assertThat(dataList).isEmpty();
+ }
+
+ @Test
+ public void getEntryData_shouldReturnDataList() {
+ final TestEntryController controller = new TestEntryController();
+ final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category").setPendingIntent(pendingIntent));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle entryData = mEntriesProvider.call(METHOD_GET_ENTRY_DATA, "uri",
+ null /* extras*/);
+
+ final ArrayList<Bundle> dataList = entryData.getParcelableArrayList(EXTRA_ENTRY_DATA);
+ assertThat(dataList).hasSize(1);
+ assertThat(dataList.get(0).getString(META_DATA_PREFERENCE_KEYHINT)).isEqualTo("123");
+ assertThat(dataList.get(0).getParcelable(META_DATA_PREFERENCE_PENDING_INTENT,
+ PendingIntent.class))
+ .isEqualTo(pendingIntent);
+ }
+
+ @Test
+ public void getSwitchData_shouldReturnDataList() {
+ final TestEntryController controller = new TestEntryController();
+ final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category").setPendingIntent(pendingIntent));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle entryData = mEntriesProvider.call(METHOD_GET_SWITCH_DATA, "uri",
+ null /* extras*/);
+
+ final ArrayList<Bundle> dataList = entryData.getParcelableArrayList(EXTRA_SWITCH_DATA);
+ assertThat(dataList).hasSize(1);
+ assertThat(dataList.get(0).getString(META_DATA_PREFERENCE_KEYHINT)).isEqualTo("123");
+ assertThat(dataList.get(0).getParcelable(META_DATA_PREFERENCE_PENDING_INTENT,
+ PendingIntent.class))
+ .isEqualTo(pendingIntent);
+ }
+
+ @Test
+ public void getEntryDataByKey_shouldReturnData() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestEntryController controller = new TestEntryController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle entryData = mEntriesProvider.call(METHOD_GET_ENTRY_DATA, "uri", extras);
+
+ assertThat(entryData.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 TestEntryController controller = new TestEntryController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle entryData = mEntriesProvider.call(METHOD_GET_SWITCH_DATA, "uri", extras);
+
+ assertThat(entryData.getString(META_DATA_PREFERENCE_KEYHINT)).isEqualTo("123");
+ }
+
+ @Test
+ public void isSwitchChecked_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"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ controller.setSwitchChecked(true);
+ Bundle result = mEntriesProvider.call(METHOD_IS_CHECKED, "uri", extras);
+
+ assertThat(result.getBoolean(EXTRA_SWITCH_CHECKED_STATE)).isTrue();
+
+ controller.setSwitchChecked(false);
+ result = mEntriesProvider.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 TestEntryController controller = new TestEntryController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle iconBundle = mEntriesProvider.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 TestEntryController controller = new TestDynamicController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle iconBundle = mEntriesProvider.call(METHOD_GET_PROVIDER_ICON, "uri", extras);
+
+ assertThat(iconBundle).isEqualTo(TestDynamicController.ICON_BUNDLE);
+ }
+
+ @Test
+ public void getDynamicTitle_noImplementInterface_shouldReturnNull() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestEntryController controller = new TestEntryController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mEntriesProvider.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 TestEntryController controller = new TestDynamicController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mEntriesProvider.call(METHOD_GET_DYNAMIC_TITLE, "uri", extras);
+
+ assertThat(result.getString(META_DATA_PREFERENCE_TITLE))
+ .isEqualTo(TestDynamicController.TITLE);
+ }
+
+ @Test
+ public void getDynamicSummary_noImplementInterface_shouldReturnNull() {
+ final Bundle extras = new Bundle();
+ extras.putString(META_DATA_PREFERENCE_KEYHINT, "123");
+ final TestEntryController controller = new TestEntryController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mEntriesProvider.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 TestEntryController controller = new TestDynamicController();
+ controller.setKey("123");
+ controller.setMetaData(new MetaData("category"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mEntriesProvider.call(METHOD_GET_DYNAMIC_SUMMARY, "uri", extras);
+
+ assertThat(result.getString(META_DATA_PREFERENCE_SUMMARY))
+ .isEqualTo(TestDynamicController.SUMMARY);
+ }
+
+ @Test
+ public void onSwitchCheckedChangedSuccess_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"));
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mEntriesProvider.call(METHOD_ON_CHECKED_CHANGED, "uri", extras);
+
+ assertThat(result.getBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR)).isFalse();
+ }
+
+ @Test
+ public void onSwitchCheckedChangedFailed_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.setSwitchErrorMessage("error");
+ mEntriesProvider.addController(controller);
+ mEntriesProvider.attachInfo(mContext, mProviderInfo);
+
+ final Bundle result = mEntriesProvider.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 static class TestEntriesProvider extends EntriesProvider {
+
+ private List<EntryController> mControllers;
+
+ @Override
+ protected List<EntryController> createEntryControllers() {
+ return mControllers;
+ }
+
+ void addController(EntryController controller) {
+ if (mControllers == null) {
+ mControllers = new ArrayList<>();
+ }
+ mControllers.add(controller);
+ }
+ }
+
+ private static class TestEntryController extends EntryController {
+
+ private String mKey;
+ private MetaData mMetaData;
+
+ @Override
+ public String getKey() {
+ return mKey;
+ }
+
+ @Override
+ protected MetaData getMetaData() {
+ return mMetaData;
+ }
+
+ void setKey(String key) {
+ mKey = key;
+ }
+
+ void setMetaData(MetaData metaData) {
+ mMetaData = metaData;
+ }
+ }
+
+ private static class TestSwitchController extends EntryController implements ProviderSwitch {
+
+ private String mKey;
+ private MetaData mMetaData;
+ private boolean mChecked;
+ private String mErrorMsg;
+
+ @Override
+ public String getKey() {
+ return mKey;
+ }
+
+ @Override
+ protected MetaData getMetaData() {
+ return mMetaData;
+ }
+
+ @Override
+ public boolean isSwitchChecked() {
+ return mChecked;
+ }
+
+ @Override
+ public boolean onSwitchCheckedChanged(boolean checked) {
+ return mErrorMsg == null ? true : false;
+ }
+
+ @Override
+ public String getSwitchErrorMessage(boolean attemptedChecked) {
+ return mErrorMsg;
+ }
+
+ void setKey(String key) {
+ mKey = key;
+ }
+
+ void setMetaData(MetaData metaData) {
+ mMetaData = metaData;
+ }
+
+ void setSwitchChecked(boolean checked) {
+ mChecked = checked;
+ }
+
+ void setSwitchErrorMessage(String errorMsg) {
+ mErrorMsg = errorMsg;
+ }
+ }
+
+ private static class TestDynamicController extends TestEntryController
+ implements ProviderIcon, DynamicTitle, DynamicSummary {
+
+ static final String TITLE = "title";
+ static final String SUMMARY = "summary";
+ static final Bundle ICON_BUNDLE = new Bundle();
+
+ @Override
+ public Bundle getProviderIcon() {
+ return ICON_BUNDLE;
+ }
+
+ @Override
+ public String getDynamicTitle() {
+ return TITLE;
+ }
+
+ @Override
+ public String getDynamicSummary() {
+ return SUMMARY;
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
index abfb407..80f9efb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
@@ -17,20 +17,24 @@
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_GROUP_KEY;
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_SWITCH_URI;
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.app.PendingIntent;
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 android.os.UserHandle;
import org.junit.Before;
import org.junit.Rule;
@@ -173,13 +177,93 @@
assertThat(tile.mLastUpdateTime).isNotEqualTo(staleTimeStamp);
}
+ @Test
+ public void hasPendingIntent_empty_returnsFalse() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.hasPendingIntent()).isFalse();
+ }
+
+ @Test
+ public void hasPendingIntent_notEmpty_returnsTrue() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+ tile.pendingIntentMap.put(
+ UserHandle.CURRENT, PendingIntent.getActivity(mContext, 0, new Intent(), 0));
+
+ assertThat(tile.hasPendingIntent()).isTrue();
+ }
+
+ @Test
+ public void hasGroupKey_empty_returnsFalse() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.hasGroupKey()).isFalse();
+ }
+
+ @Test
+ public void hasGroupKey_notEmpty_returnsTrue() {
+ mMetaData.putString(META_DATA_PREFERENCE_GROUP_KEY, "test_key");
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.hasGroupKey()).isTrue();
+ }
+
+ @Test
+ public void getGroupKey_empty_returnsNull() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.getGroupKey()).isNull();
+ }
+
+ @Test
+ public void getGroupKey_notEmpty_returnsValue() {
+ mMetaData.putString(META_DATA_PREFERENCE_GROUP_KEY, "test_key");
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.getGroupKey()).isEqualTo("test_key");
+ }
+
+ @Test
+ public void getType_withSwitch_returnsSwitch() {
+ mMetaData.putString(META_DATA_PREFERENCE_SWITCH_URI, "test://testabc/");
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.getType()).isEqualTo(Tile.Type.SWITCH);
+ }
+
+ @Test
+ public void getType_withSwitchAndPendingIntent_returnsSwitchWithAction() {
+ mMetaData.putString(META_DATA_PREFERENCE_SWITCH_URI, "test://testabc/");
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+ tile.pendingIntentMap.put(
+ UserHandle.CURRENT, PendingIntent.getActivity(mContext, 0, new Intent(), 0));
+
+ assertThat(tile.getType()).isEqualTo(Tile.Type.SWITCH_WITH_ACTION);
+ }
+
+ @Test
+ public void getType_withPendingIntent_returnsExternalAction() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+ tile.pendingIntentMap.put(
+ UserHandle.CURRENT, PendingIntent.getActivity(mContext, 0, new Intent(), 0));
+
+ assertThat(tile.getType()).isEqualTo(Tile.Type.EXTERNAL_ACTION);
+ }
+
+ @Test
+ public void getType_withoutSwitchAndPendingIntent_returnsGroup() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.getType()).isEqualTo(Tile.Type.GROUP);
+ }
+
@Implements(TileUtils.class)
private static class ShadowTileUtils {
private static Bundle sMetaData;
@Implementation
- protected static Bundle getSwitchDataFromProvider(Context context, String authority,
+ protected static Bundle getEntryDataFromProvider(Context context, String authority,
String key) {
return sMetaData;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 906e06e..2086466 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -21,6 +21,7 @@
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
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_PENDING_INTENT;
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.PROFILE_ALL;
@@ -40,6 +41,7 @@
import static org.robolectric.RuntimeEnvironment.application;
import android.app.ActivityManager;
+import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -350,6 +352,53 @@
assertThat(outTiles).isEmpty();
}
+ @Test
+ public void loadTilesForAction_multipleUserProfiles_updatesUserHandle() {
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+ URI_GET_SUMMARY, null, 123, PROFILE_ALL);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
+ .thenReturn(info);
+
+ TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION,
+ addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */);
+ TileUtils.loadTilesForAction(mContext, new UserHandle(10), IA_SETTINGS_ACTION,
+ addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */);
+
+ assertThat(outTiles).hasSize(1);
+ assertThat(outTiles.get(0).userHandle)
+ .containsExactly(UserHandle.CURRENT, new UserHandle(10));
+ }
+
+ @Test
+ public void loadTilesForAction_withPendingIntent_updatesPendingIntentMap() {
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON,
+ URI_GET_SUMMARY, null, 123, PROFILE_ALL);
+ PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ resolveInfo.activityInfo.metaData
+ .putParcelable(META_DATA_PREFERENCE_PENDING_INTENT, pendingIntent);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()))
+ .thenReturn(info);
+
+ TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION,
+ addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */);
+ TileUtils.loadTilesForAction(mContext, new UserHandle(10), IA_SETTINGS_ACTION,
+ addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */);
+
+ assertThat(outTiles).hasSize(1);
+ assertThat(outTiles.get(0).pendingIntentMap).containsExactly(
+ UserHandle.CURRENT, pendingIntent, new UserHandle(10), pendingIntent);
+ }
+
public static ResolveInfo newInfo(boolean systemApp, String category) {
return newInfo(systemApp, category, null);
}
@@ -424,7 +473,7 @@
private static Bundle sMetaData;
@Implementation
- protected static List<Bundle> getSwitchDataFromProvider(Context context, String authority) {
+ protected static List<Bundle> getEntryDataFromProvider(Context context, String authority) {
return Arrays.asList(sMetaData);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index a431a59..a90980f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -16,6 +16,7 @@
package com.android.systemui.dagger;
+import com.android.systemui.globalactions.ShutdownUiModule;
import com.android.systemui.keyguard.CustomizationProvider;
import com.android.systemui.statusbar.NotificationInsetsModule;
import com.android.systemui.statusbar.QsFrameTranslateModule;
@@ -31,6 +32,7 @@
DependencyProvider.class,
NotificationInsetsModule.class,
QsFrameTranslateModule.class,
+ ShutdownUiModule.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUICoreStartableModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d6c0829..498e597 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -221,7 +221,7 @@
// TODO(b/267722622): Tracking Bug
@JvmField
val WALLPAPER_PICKER_UI_FOR_AIWP =
- unreleasedFlag(
+ releasedFlag(
229,
"wallpaper_picker_ui_for_aiwp"
)
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 290bf0d..c5027cc 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -15,27 +15,12 @@
package com.android.systemui.globalactions;
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.app.Dialog;
import android.content.Context;
-import android.os.PowerManager;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import com.android.internal.R;
-import com.android.settingslib.Utils;
import com.android.systemui.plugins.GlobalActions;
-import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -50,12 +35,14 @@
private final CommandQueue mCommandQueue;
private final GlobalActionsDialogLite mGlobalActionsDialog;
private boolean mDisabled;
+ private ShutdownUi mShutdownUi;
@Inject
public GlobalActionsImpl(Context context, CommandQueue commandQueue,
GlobalActionsDialogLite globalActionsDialog, BlurUtils blurUtils,
KeyguardStateController keyguardStateController,
- DeviceProvisionedController deviceProvisionedController) {
+ DeviceProvisionedController deviceProvisionedController,
+ ShutdownUi shutdownUi) {
mContext = context;
mGlobalActionsDialog = globalActionsDialog;
mKeyguardStateController = keyguardStateController;
@@ -63,6 +50,7 @@
mCommandQueue = commandQueue;
mBlurUtils = blurUtils;
mCommandQueue.addCallback(this);
+ mShutdownUi = shutdownUi;
}
@Override
@@ -80,103 +68,8 @@
@Override
public void showShutdownUi(boolean isReboot, String reason) {
- ScrimDrawable background = new ScrimDrawable();
-
- final Dialog d = new Dialog(mContext,
- com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
-
- d.setOnShowListener(dialog -> {
- if (mBlurUtils.supportsBlursOnWindows()) {
- int backgroundAlpha = (int) (ScrimController.BUSY_SCRIM_ALPHA * 255);
- background.setAlpha(backgroundAlpha);
- mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
- (int) mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
- } else {
- float backgroundAlpha = mContext.getResources().getFloat(
- com.android.systemui.R.dimen.shutdown_scrim_behind_alpha);
- background.setAlpha((int) (backgroundAlpha * 255));
- }
- });
-
- // Window initialization
- Window window = d.getWindow();
- window.requestFeature(Window.FEATURE_NO_TITLE);
- window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- // Inflate the decor view, so the attributes below are not overwritten by the theme.
- window.getDecorView();
- window.getAttributes().width = ViewGroup.LayoutParams.MATCH_PARENT;
- window.getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
- window.getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- window.getAttributes().setFitInsetsTypes(0 /* types */);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- window.addFlags(
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- window.setBackgroundDrawable(background);
- window.setWindowAnimations(com.android.systemui.R.style.Animation_ShutdownUi);
-
- d.setContentView(R.layout.shutdown_dialog);
- d.setCancelable(false);
-
- int color;
- if (mBlurUtils.supportsBlursOnWindows()) {
- color = Utils.getColorAttrDefaultColor(mContext,
- com.android.systemui.R.attr.wallpaperTextColor);
- } else {
- color = mContext.getResources().getColor(
- com.android.systemui.R.color.global_actions_shutdown_ui_text);
- }
-
- ProgressBar bar = d.findViewById(R.id.progress);
- bar.getIndeterminateDrawable().setTint(color);
-
- TextView reasonView = d.findViewById(R.id.text1);
- TextView messageView = d.findViewById(R.id.text2);
-
- reasonView.setTextColor(color);
- messageView.setTextColor(color);
-
- messageView.setText(getRebootMessage(isReboot, reason));
- String rebootReasonMessage = getReasonMessage(reason);
- if (rebootReasonMessage != null) {
- reasonView.setVisibility(View.VISIBLE);
- reasonView.setText(rebootReasonMessage);
- }
-
- d.show();
+ mShutdownUi.showShutdownUi(isReboot, reason);
}
-
- @StringRes
- private int getRebootMessage(boolean isReboot, @Nullable String reason) {
- if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
- return R.string.reboot_to_update_reboot;
- } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
- return R.string.reboot_to_reset_message;
- } else if (isReboot) {
- return R.string.reboot_to_reset_message;
- } else {
- return R.string.shutdown_progress;
- }
- }
-
- @Nullable
- private String getReasonMessage(@Nullable String reason) {
- if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
- return mContext.getString(R.string.reboot_to_update_title);
- } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
- return mContext.getString(R.string.reboot_to_reset_title);
- } else {
- return null;
- }
- }
-
@Override
public void disable(int displayId, int state1, int state2, boolean animate) {
final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
new file mode 100644
index 0000000..8125d70
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2023 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.systemui.globalactions;
+
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.PowerManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.internal.R;
+import com.android.settingslib.Utils;
+import com.android.systemui.scrim.ScrimDrawable;
+import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.phone.ScrimController;
+
+/**
+ * Provides the UI shown during system shutdown.
+ */
+public class ShutdownUi {
+
+ private Context mContext;
+ private BlurUtils mBlurUtils;
+ public ShutdownUi(Context context, BlurUtils blurUtils) {
+ mContext = context;
+ mBlurUtils = blurUtils;
+ }
+
+ /**
+ * Display the shutdown UI.
+ * @param isReboot Whether the device will be rebooting after this shutdown.
+ * @param reason Cause for the shutdown.
+ */
+ public void showShutdownUi(boolean isReboot, String reason) {
+ ScrimDrawable background = new ScrimDrawable();
+
+ final Dialog d = new Dialog(mContext,
+ com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
+
+ d.setOnShowListener(dialog -> {
+ if (mBlurUtils.supportsBlursOnWindows()) {
+ int backgroundAlpha = (int) (ScrimController.BUSY_SCRIM_ALPHA * 255);
+ background.setAlpha(backgroundAlpha);
+ mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
+ (int) mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
+ } else {
+ float backgroundAlpha = mContext.getResources().getFloat(
+ com.android.systemui.R.dimen.shutdown_scrim_behind_alpha);
+ background.setAlpha((int) (backgroundAlpha * 255));
+ }
+ });
+
+ // Window initialization
+ Window window = d.getWindow();
+ window.requestFeature(Window.FEATURE_NO_TITLE);
+ window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ // Inflate the decor view, so the attributes below are not overwritten by the theme.
+ window.getDecorView();
+ window.getAttributes().width = ViewGroup.LayoutParams.MATCH_PARENT;
+ window.getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
+ window.getAttributes().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ window.getAttributes().setFitInsetsTypes(0 /* types */);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ window.addFlags(
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ window.setBackgroundDrawable(background);
+ window.setWindowAnimations(com.android.systemui.R.style.Animation_ShutdownUi);
+
+ d.setContentView(getShutdownDialogContent());
+ d.setCancelable(false);
+
+ int color;
+ if (mBlurUtils.supportsBlursOnWindows()) {
+ color = Utils.getColorAttrDefaultColor(mContext,
+ com.android.systemui.R.attr.wallpaperTextColor);
+ } else {
+ color = mContext.getResources().getColor(
+ com.android.systemui.R.color.global_actions_shutdown_ui_text);
+ }
+
+ ProgressBar bar = d.findViewById(R.id.progress);
+ bar.getIndeterminateDrawable().setTint(color);
+
+ TextView reasonView = d.findViewById(R.id.text1);
+ TextView messageView = d.findViewById(R.id.text2);
+
+ reasonView.setTextColor(color);
+ messageView.setTextColor(color);
+
+ messageView.setText(getRebootMessage(isReboot, reason));
+ String rebootReasonMessage = getReasonMessage(reason);
+ if (rebootReasonMessage != null) {
+ reasonView.setVisibility(View.VISIBLE);
+ reasonView.setText(rebootReasonMessage);
+ }
+
+ d.show();
+ }
+
+ public int getShutdownDialogContent() {
+ return R.layout.shutdown_dialog;
+ }
+
+ @StringRes
+ @VisibleForTesting int getRebootMessage(boolean isReboot, @Nullable String reason) {
+ if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+ return R.string.reboot_to_update_reboot;
+ } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+ return R.string.reboot_to_reset_message;
+ } else if (isReboot) {
+ return R.string.reboot_to_reset_message;
+ } else {
+ return R.string.shutdown_progress;
+ }
+ }
+
+ @Nullable
+ @VisibleForTesting String getReasonMessage(@Nullable String reason) {
+ if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+ return mContext.getString(R.string.reboot_to_update_title);
+ } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+ return mContext.getString(R.string.reboot_to_reset_title);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt
new file mode 100644
index 0000000..b7285da
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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.systemui.globalactions
+
+import android.content.Context
+import com.android.systemui.statusbar.BlurUtils
+import dagger.Module
+import dagger.Provides
+
+/** Provides the UI shown during system shutdown. */
+@Module
+class ShutdownUiModule {
+ /** Shutdown UI provider. */
+ @Provides
+ fun provideShutdownUi(context: Context?, blurUtils: BlurUtils?): ShutdownUi {
+ return ShutdownUi(context, blurUtils)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index 640adcc..5e489b0 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -20,15 +20,14 @@
import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.SystemUIBinder;
import com.android.systemui.dagger.SystemUIModule;
+import com.android.systemui.globalactions.ShutdownUiModule;
+import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.recents.RecentsModule;
import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.row.NotificationRowModule;
-import com.android.systemui.keyguard.dagger.KeyguardModule;
-import com.android.systemui.recents.RecentsModule;
-
import dagger.Subcomponent;
/**
@@ -43,6 +42,7 @@
NotificationRowModule.class,
NotificationsModule.class,
RecentsModule.class,
+ ShutdownUiModule.class,
SystemUIModule.class,
TvSystemUIBinder.class,
TVSystemUICoreStartableModule.class,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
new file mode 100644
index 0000000..9d9b263
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 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.systemui.globalactions;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import android.os.PowerManager;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.BlurUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ShutdownUiTest extends SysuiTestCase {
+
+ ShutdownUi mShutdownUi;
+ @Mock
+ BlurUtils mBlurUtils;
+
+ @Before
+ public void setUp() throws Exception {
+ mShutdownUi = new ShutdownUi(getContext(), mBlurUtils);
+ }
+
+ @Test
+ public void getRebootMessage_update() {
+ int messageId = mShutdownUi.getRebootMessage(true, PowerManager.REBOOT_RECOVERY_UPDATE);
+ assertEquals(messageId, R.string.reboot_to_update_reboot);
+ }
+
+ @Test
+ public void getRebootMessage_rebootDefault() {
+ int messageId = mShutdownUi.getRebootMessage(true, "anything-else");
+ assertEquals(messageId, R.string.reboot_to_reset_message);
+ }
+
+ @Test
+ public void getRebootMessage_shutdown() {
+ int messageId = mShutdownUi.getRebootMessage(false, "anything-else");
+ assertEquals(messageId, R.string.shutdown_progress);
+ }
+
+ @Test
+ public void getReasonMessage_update() {
+ String message = mShutdownUi.getReasonMessage(PowerManager.REBOOT_RECOVERY_UPDATE);
+ assertEquals(message, mContext.getString(R.string.reboot_to_update_title));
+ }
+
+ @Test
+ public void getReasonMessage_rebootDefault() {
+ String message = mShutdownUi.getReasonMessage(PowerManager.REBOOT_RECOVERY);
+ assertEquals(message, mContext.getString(R.string.reboot_to_reset_title));
+ }
+
+ @Test
+ public void getRebootMessage_defaultToNone() {
+ String message = mShutdownUi.getReasonMessage("anything-else");
+ assertNull(message);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 778951a..98ee98b 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -248,7 +248,10 @@
Slog.e(TAG, "WM sent Transaction to organized, but never received" +
" commit callback. Application ANR likely to follow.");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- onCommitted(merged);
+ synchronized (mWm.mGlobalLock) {
+ onCommitted(merged.mNativeObject != 0
+ ? merged : mWm.mTransactionFactory.get());
+ }
}
};
CommitCallback callback = new CommitCallback();