Deprecating RemoteViewsAdapter in RemoteViews
Also hiding the feature behind a flag Bug: 245950570 Test: Manual Change-Id: I52420b2c4cb5a0691257c08870d7446102beabb1
This commit is contained in:
@@ -17,3 +17,4 @@
|
||||
package android.widget;
|
||||
|
||||
parcelable RemoteViews;
|
||||
parcelable RemoteViews.RemoteCollectionItems;
|
||||
|
||||
@@ -33,16 +33,19 @@ import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.Application;
|
||||
import android.app.LoadedApk;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.ColorStateList;
|
||||
@@ -65,10 +68,12 @@ import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.StrictMode;
|
||||
import android.os.UserHandle;
|
||||
import android.system.Os;
|
||||
@@ -98,8 +103,10 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||
import com.android.internal.util.ContrastColorUtil;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.widget.IRemoteViewsFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileDescriptor;
|
||||
@@ -124,7 +131,9 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -323,6 +332,13 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
private static final LayoutInflater.Filter INFLATER_FILTER =
|
||||
(clazz) -> clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
|
||||
|
||||
/**
|
||||
* The maximum waiting time for remote adapter conversion in milliseconds
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private static final int MAX_ADAPTER_CONVERSION_WAITING_TIME_MS = 2000;
|
||||
|
||||
/**
|
||||
* Application that hosts the remote views.
|
||||
*
|
||||
@@ -1042,28 +1058,96 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
|
||||
private class SetRemoteCollectionItemListAdapterAction extends Action {
|
||||
private final RemoteCollectionItems mItems;
|
||||
private @NonNull CompletableFuture<RemoteCollectionItems> mItemsFuture;
|
||||
|
||||
SetRemoteCollectionItemListAdapterAction(@IdRes int id, RemoteCollectionItems items) {
|
||||
SetRemoteCollectionItemListAdapterAction(@IdRes int id,
|
||||
@NonNull RemoteCollectionItems items) {
|
||||
viewId = id;
|
||||
mItems = items;
|
||||
mItems.setHierarchyRootData(getHierarchyRootData());
|
||||
items.setHierarchyRootData(getHierarchyRootData());
|
||||
mItemsFuture = CompletableFuture.completedFuture(items);
|
||||
}
|
||||
|
||||
SetRemoteCollectionItemListAdapterAction(@IdRes int id, Intent intent) {
|
||||
viewId = id;
|
||||
mItemsFuture = getItemsFutureFromIntentWithTimeout(intent);
|
||||
setHierarchyRootData(getHierarchyRootData());
|
||||
}
|
||||
|
||||
private static CompletableFuture<RemoteCollectionItems> getItemsFutureFromIntentWithTimeout(
|
||||
Intent intent) {
|
||||
if (intent == null) {
|
||||
Log.e(LOG_TAG, "Null intent received when generating adapter future");
|
||||
return CompletableFuture.completedFuture(new RemoteCollectionItems
|
||||
.Builder().build());
|
||||
}
|
||||
|
||||
final Context context = ActivityThread.currentApplication();
|
||||
final CompletableFuture<RemoteCollectionItems> result = new CompletableFuture<>();
|
||||
|
||||
context.bindService(intent, Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE),
|
||||
result.defaultExecutor(), new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName,
|
||||
IBinder iBinder) {
|
||||
RemoteCollectionItems items;
|
||||
try {
|
||||
items = IRemoteViewsFactory.Stub.asInterface(iBinder)
|
||||
.getRemoteCollectionItems();
|
||||
} catch (RemoteException re) {
|
||||
items = new RemoteCollectionItems.Builder().build();
|
||||
Log.e(LOG_TAG, "Error getting collection items from the factory",
|
||||
re);
|
||||
} finally {
|
||||
context.unbindService(this);
|
||||
}
|
||||
|
||||
result.complete(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName componentName) { }
|
||||
});
|
||||
|
||||
result.completeOnTimeout(
|
||||
new RemoteCollectionItems.Builder().build(),
|
||||
MAX_ADAPTER_CONVERSION_WAITING_TIME_MS, TimeUnit.MILLISECONDS);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SetRemoteCollectionItemListAdapterAction(Parcel parcel) {
|
||||
viewId = parcel.readInt();
|
||||
mItems = new RemoteCollectionItems(parcel, getHierarchyRootData());
|
||||
mItemsFuture = CompletableFuture.completedFuture(
|
||||
new RemoteCollectionItems(parcel, getHierarchyRootData()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHierarchyRootData(HierarchyRootData rootData) {
|
||||
mItems.setHierarchyRootData(rootData);
|
||||
mItemsFuture = mItemsFuture
|
||||
.thenApply(rc -> {
|
||||
rc.setHierarchyRootData(rootData);
|
||||
return rc;
|
||||
});
|
||||
}
|
||||
|
||||
private static RemoteCollectionItems getCollectionItemsFromFuture(
|
||||
CompletableFuture<RemoteCollectionItems> itemsFuture) {
|
||||
RemoteCollectionItems items;
|
||||
try {
|
||||
items = itemsFuture.get();
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error getting collection items from future", e);
|
||||
items = new RemoteCollectionItems.Builder().build();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(viewId);
|
||||
mItems.writeToParcel(dest, flags, /* attached= */ true);
|
||||
RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture);
|
||||
items.writeToParcel(dest, flags, /* attached= */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1072,6 +1156,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
View target = root.findViewById(viewId);
|
||||
if (target == null) return;
|
||||
|
||||
RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture);
|
||||
|
||||
// Ensure that we are applying to an AppWidget root
|
||||
if (!(rootParent instanceof AppWidgetHostView)) {
|
||||
Log.e(LOG_TAG, "setRemoteAdapter can only be used for "
|
||||
@@ -1092,10 +1178,10 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
// recycling in setAdapter, so we must call setAdapter again if the number of view types
|
||||
// increases.
|
||||
if (adapter instanceof RemoteCollectionItemsAdapter
|
||||
&& adapter.getViewTypeCount() >= mItems.getViewTypeCount()) {
|
||||
&& adapter.getViewTypeCount() >= items.getViewTypeCount()) {
|
||||
try {
|
||||
((RemoteCollectionItemsAdapter) adapter).setData(
|
||||
mItems, params.handler, params.colorResources);
|
||||
items, params.handler, params.colorResources);
|
||||
} catch (Throwable throwable) {
|
||||
// setData should never failed with the validation in the items builder, but if
|
||||
// it does, catch and rethrow.
|
||||
@@ -1105,7 +1191,7 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
|
||||
try {
|
||||
adapterView.setAdapter(new RemoteCollectionItemsAdapter(mItems,
|
||||
adapterView.setAdapter(new RemoteCollectionItemsAdapter(items,
|
||||
params.handler, params.colorResources));
|
||||
} catch (Throwable throwable) {
|
||||
// This could throw if the AdapterView somehow doesn't accept BaseAdapter due to
|
||||
@@ -4679,6 +4765,12 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
* providing data to the RemoteViewsAdapter
|
||||
*/
|
||||
public void setRemoteAdapter(@IdRes int viewId, Intent intent) {
|
||||
if (AppGlobals.getIntCoreSetting(
|
||||
SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
|
||||
SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT ? 1 : 0) == 1) {
|
||||
addAction(new SetRemoteCollectionItemListAdapterAction(viewId, intent));
|
||||
return;
|
||||
}
|
||||
addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,13 @@ public abstract class RemoteViewsService extends Service {
|
||||
new HashMap<Intent.FilterComparison, RemoteViewsFactory>();
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
/**
|
||||
* Used for determining the maximum number of entries to retrieve from RemoteViewsFactory
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private static final int MAX_NUM_ENTRY = 25;
|
||||
|
||||
/**
|
||||
* An interface for an adapter between a remote collection view (ListView, GridView, etc) and
|
||||
* the underlying data for that view. The implementor is responsible for making a RemoteView
|
||||
@@ -227,6 +234,30 @@ public abstract class RemoteViewsService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteViews.RemoteCollectionItems getRemoteCollectionItems() {
|
||||
RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
|
||||
.Builder().build();
|
||||
|
||||
try {
|
||||
RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
|
||||
new RemoteViews.RemoteCollectionItems.Builder();
|
||||
mFactory.onDataSetChanged();
|
||||
|
||||
itemsBuilder.setHasStableIds(mFactory.hasStableIds());
|
||||
final int numOfEntries = Math.min(mFactory.getCount(), MAX_NUM_ENTRY);
|
||||
for (int i = 0; i < numOfEntries; i++) {
|
||||
itemsBuilder.addItem(mFactory.getItemId(i), mFactory.getViewAt(i));
|
||||
}
|
||||
|
||||
items = itemsBuilder.build();
|
||||
} catch (Exception ex) {
|
||||
Thread t = Thread.currentThread();
|
||||
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private RemoteViewsFactory mFactory;
|
||||
private boolean mIsCreated;
|
||||
}
|
||||
|
||||
@@ -531,6 +531,17 @@ public final class SystemUiDeviceConfigFlags {
|
||||
*/
|
||||
public static final String TASK_MANAGER_SHOW_FOOTER_DOT = "task_manager_show_footer_dot";
|
||||
|
||||
/**
|
||||
* (boolean) Whether to enable the adapter conversion in RemoteViews
|
||||
*/
|
||||
public static final String REMOTEVIEWS_ADAPTER_CONVERSION = "remoteviews_adapter_conversion";
|
||||
|
||||
/**
|
||||
* Default value for whether the adapter conversion is enabled or not. This is set for
|
||||
* RemoteViews and should not be a common practice.
|
||||
*/
|
||||
public static final boolean REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT = false;
|
||||
|
||||
/**
|
||||
* (boolean) Whether the task manager should show a stop button if the app is allowlisted
|
||||
* by the user.
|
||||
|
||||
@@ -39,5 +39,6 @@ interface IRemoteViewsFactory {
|
||||
boolean hasStableIds();
|
||||
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
|
||||
boolean isCreated();
|
||||
RemoteViews.RemoteCollectionItems getRemoteCollectionItems();
|
||||
}
|
||||
|
||||
|
||||
@@ -353,6 +353,23 @@ public class RemoteViewsAdapterTest {
|
||||
public boolean isCreated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteViews.RemoteCollectionItems getRemoteCollectionItems() {
|
||||
RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
|
||||
new RemoteViews.RemoteCollectionItems.Builder();
|
||||
itemsBuilder.setHasStableIds(hasStableIds())
|
||||
.setViewTypeCount(getViewTypeCount());
|
||||
try {
|
||||
for (int i = 0; i < mCount; i++) {
|
||||
itemsBuilder.addItem(getItemId(i), getViewAt(i));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
return itemsBuilder.build();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DistinctIntent extends Intent {
|
||||
|
||||
Reference in New Issue
Block a user