Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25002046 authored by Sihua Ma's avatar Sihua Ma Committed by Android (Google) Code Review
Browse files

Merge "Deprecating RemoteViewsAdapter in RemoteViews" into udc-qpr-dev

parents 78aa3440 24c3cc53
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -17,3 +17,4 @@
package android.widget;

parcelable RemoteViews;
parcelable RemoteViews.RemoteCollectionItems;
+102 −10
Original line number Diff line number Diff line
@@ -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));
    }

+31 −0
Original line number Diff line number Diff line
@@ -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;
    }
+11 −0
Original line number Diff line number Diff line
@@ -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.
+1 −0
Original line number Diff line number Diff line
@@ -39,5 +39,6 @@ interface IRemoteViewsFactory {
    boolean hasStableIds();
    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
    boolean isCreated();
    RemoteViews.RemoteCollectionItems getRemoteCollectionItems();
}
Loading