diff options
| author | Pierre Barbier de Reuille <pbdr@google.com> | 2021-02-09 15:59:41 +0000 |
|---|---|---|
| committer | Pierre Barbier de Reuille <pbdr@google.com> | 2021-02-24 15:13:29 +0000 |
| commit | 4219de7ded64971f100f9187b3c6a75e03073152 (patch) | |
| tree | 4b04be6bcba2c92789be67dcbf7c690bb539806c /core/java/android/widget/RemoteViews.java | |
| parent | 5f630223cc91a813a8b35cded57513274b20932d (diff) | |
Framework implementation of go/widgets-dynamic-colors
Bug: 179783721
Test: atest CtsWidgetTestCases:android.widget.cts.RemoteViewsThemeColorsTest
Change-Id: I622e79ed8738dc862790191bf9fcf44b0af35c8e
Diffstat (limited to 'core/java/android/widget/RemoteViews.java')
| -rw-r--r-- | core/java/android/widget/RemoteViews.java | 347 |
1 files changed, 262 insertions, 85 deletions
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 514471783c6a..e0b4ec71b0a0 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -46,6 +46,8 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.content.res.loader.ResourcesLoader; +import android.content.res.loader.ResourcesProvider; import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Outline; @@ -62,16 +64,19 @@ import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Parcel; +import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.Process; import android.os.StrictMode; import android.os.UserHandle; +import android.system.Os; import android.text.TextUtils; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.IntArray; import android.util.Log; import android.util.Pair; +import android.util.SparseIntArray; import android.util.TypedValue; import android.util.TypedValue.ComplexDimensionUnit; import android.view.ContextThemeWrapper; @@ -92,6 +97,12 @@ import com.android.internal.R; import com.android.internal.util.ContrastColorUtil; import com.android.internal.util.Preconditions; +import java.io.ByteArrayOutputStream; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -520,8 +531,8 @@ public class RemoteViews implements Parcelable, Filter { * SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!! */ private abstract static class Action implements Parcelable { - public abstract void apply(View root, ViewGroup rootParent, - InteractionHandler handler) throws ActionException; + public abstract void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException; public static final int MERGE_REPLACE = 0; public static final int MERGE_APPEND = 1; @@ -551,8 +562,8 @@ public class RemoteViews implements Parcelable, Filter { * and return the final action which will run on the UI thread. * Override this if some of the tasks can be performed async. */ - public Action initActionAsync( - ViewTree root, ViewGroup rootParent, InteractionHandler handler) { + public Action initActionAsync(ViewTree root, ViewGroup rootParent, + InteractionHandler handler, ColorResources colorResources) { return this; } @@ -595,7 +606,9 @@ public class RemoteViews implements Parcelable, Filter { // Constant used during async execution. It is not parcelable. private static final Action ACTION_NOOP = new RuntimeAction() { @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { } + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { + } }; /** @@ -713,7 +726,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View view = root.findViewById(viewId); if (!(view instanceof AdapterView<?>)) return; @@ -748,7 +762,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, final InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; @@ -820,7 +835,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; @@ -843,7 +859,8 @@ public class RemoteViews implements Parcelable, Filter { if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) { ((RemoteViewsListAdapter) a).setViewsList(list); } else { - v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount)); + v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount, + colorResources)); } } else if (target instanceof AdapterViewAnimator) { AdapterViewAnimator v = (AdapterViewAnimator) target; @@ -851,7 +868,8 @@ public class RemoteViews implements Parcelable, Filter { if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) { ((RemoteViewsListAdapter) a).setViewsList(list); } else { - v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount)); + v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount, + colorResources)); } } } @@ -882,7 +900,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; @@ -919,7 +938,7 @@ public class RemoteViews implements Parcelable, Filter { @Override public Action initActionAsync(ViewTree root, ViewGroup rootParent, - InteractionHandler handler) { + InteractionHandler handler, ColorResources colorResources) { SetRemoteViewsAdapterIntent copy = new SetRemoteViewsAdapterIntent(viewId, intent); copy.isAsync = true; return copy; @@ -958,7 +977,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, final InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; @@ -1037,7 +1057,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, final InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; if (!(target instanceof CompoundButton)) { @@ -1240,7 +1261,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; @@ -1297,7 +1319,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; @@ -1334,7 +1357,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View view = root.findViewById(viewId); if (view == null) return; @@ -1437,12 +1461,12 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, - InteractionHandler handler) throws ActionException { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException { ReflectionAction ra = new ReflectionAction(viewId, methodName, BaseReflectionAction.BITMAP, bitmap); - ra.apply(root, rootParent, handler); + ra.apply(root, rootParent, handler, colorResources); } @Override @@ -1518,7 +1542,8 @@ public class RemoteViews implements Parcelable, Filter { protected abstract Object getParameterValue(@Nullable View view) throws ActionException; @Override - public final void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public final void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View view = root.findViewById(viewId); if (view == null) return; @@ -1536,7 +1561,7 @@ public class RemoteViews implements Parcelable, Filter { @Override public final Action initActionAsync(ViewTree root, ViewGroup rootParent, - InteractionHandler handler) { + InteractionHandler handler, ColorResources colorResources) { final View view = root.findViewById(viewId); if (view == null) return ACTION_NOOP; @@ -1938,7 +1963,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { mRunnable.run(); } } @@ -1993,7 +2019,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final Context context = root.getContext(); final ViewGroup target = root.findViewById(viewId); @@ -2002,12 +2029,14 @@ public class RemoteViews implements Parcelable, Filter { } // Inflate nested views and add as children - target.addView(mNestedViews.apply(context, target, handler), mIndex); + target.addView( + mNestedViews.apply(context, target, handler, null /* size */, colorResources), + mIndex); } @Override public Action initActionAsync(ViewTree root, ViewGroup rootParent, - InteractionHandler handler) { + InteractionHandler handler, ColorResources colorResources) { // In the async implementation, update the view tree so that subsequent calls to // findViewById return the current view. root.createTree(); @@ -2019,8 +2048,8 @@ public class RemoteViews implements Parcelable, Filter { // Inflate nested views and perform all the async tasks for the child remoteView. final Context context = root.mRoot.getContext(); - final AsyncApplyTask task = mNestedViews.getAsyncApplyTask( - context, targetVg, null, handler); + final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(context, targetVg, + null /* listener */, handler, null /* size */, colorResources); final ViewTree tree = task.doInBackground(); if (tree == null) { @@ -2033,8 +2062,8 @@ public class RemoteViews implements Parcelable, Filter { return new RuntimeAction() { @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) - throws ActionException { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException { task.onPostExecute(tree); targetVg.addView(task.mResult, mIndex); } @@ -2095,7 +2124,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final ViewGroup target = root.findViewById(viewId); if (target == null) { @@ -2112,7 +2142,7 @@ public class RemoteViews implements Parcelable, Filter { @Override public Action initActionAsync(ViewTree root, ViewGroup rootParent, - InteractionHandler handler) { + InteractionHandler handler, ColorResources colorResources) { // In the async implementation, update the view tree so that subsequent calls to // findViewById return the current view. root.createTree(); @@ -2136,8 +2166,8 @@ public class RemoteViews implements Parcelable, Filter { } return new RuntimeAction() { @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) - throws ActionException { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException { if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) { targetVg.removeAllViews(); return; @@ -2192,7 +2222,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null || target == root) { @@ -2207,7 +2238,7 @@ public class RemoteViews implements Parcelable, Filter { @Override public Action initActionAsync(ViewTree root, ViewGroup rootParent, - InteractionHandler handler) { + InteractionHandler handler, ColorResources colorResources) { // In the async implementation, update the view tree so that subsequent calls to // findViewById return the correct view. root.createTree(); @@ -2226,8 +2257,8 @@ public class RemoteViews implements Parcelable, Filter { parent.mChildren.remove(target); return new RuntimeAction() { @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) - throws ActionException { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException { parentVg.removeView(target.mRoot); } }; @@ -2306,7 +2337,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final TextView target = root.findViewById(viewId); if (target == null) return; if (drawablesLoaded) { @@ -2337,7 +2369,7 @@ public class RemoteViews implements Parcelable, Filter { @Override public Action initActionAsync(ViewTree root, ViewGroup rootParent, - InteractionHandler handler) { + InteractionHandler handler, ColorResources colorResources) { final TextView target = root.findViewById(viewId); if (target == null) return ACTION_NOOP; @@ -2415,7 +2447,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final TextView target = root.findViewById(viewId); if (target == null) return; target.setTextSize(units, size); @@ -2460,7 +2493,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; target.setPadding(left, top, right, bottom); @@ -2533,7 +2567,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) { return; @@ -2646,7 +2681,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(viewId); if (target == null) return; @@ -2681,7 +2717,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { // Let's traverse the viewtree and override all textColors! Stack<View> viewsToProcess = new Stack<>(); viewsToProcess.add(root); @@ -2731,7 +2768,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) { final View target = root.findViewById(mViewId); if (target == null) return; @@ -2765,7 +2803,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException { final View target = root.findViewById(viewId); if (target == null) return; @@ -2816,8 +2855,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) - throws ActionException { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException { final View target = root.findViewById(viewId); if (target == null) return; @@ -2893,8 +2932,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void apply(View root, ViewGroup rootParent, InteractionHandler handler) - throws ActionException { + public void apply(View root, ViewGroup rootParent, InteractionHandler handler, + ColorResources colorResources) throws ActionException { final View target = root.findViewById(viewId); if (target == null) return; @@ -4662,7 +4701,7 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, parent); - rvToApply.performApply(result, parent, handler); + rvToApply.performApply(result, parent, handler, null); return result; } @@ -4674,27 +4713,39 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public View applyWithTheme(@NonNull Context context, @NonNull ViewGroup parent, - @Nullable InteractionHandler handler, - @StyleRes int applyThemeResId, + @Nullable InteractionHandler handler, @StyleRes int applyThemeResId, @Nullable PointF size) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); - View result = inflateView(context, rvToApply, parent, applyThemeResId); - rvToApply.performApply(result, parent, handler); + View result = inflateView(context, rvToApply, parent, applyThemeResId, null); + rvToApply.performApply(result, parent, handler, null); + return result; + } + + /** @hide */ + public View apply(Context context, ViewGroup parent, InteractionHandler handler, + @NonNull PointF size, @Nullable ColorResources colorResources) { + RemoteViews rvToApply = getRemoteViewsToApply(context, size); + + View result = inflateView(context, rvToApply, parent, 0, colorResources); + rvToApply.performApply(result, parent, handler, colorResources); return result; } private View inflateView(Context context, RemoteViews rv, ViewGroup parent) { - return inflateView(context, rv, parent, 0); + return inflateView(context, rv, parent, 0, null); } private View inflateView(Context context, RemoteViews rv, ViewGroup parent, - @StyleRes int applyThemeResId) { + @StyleRes int applyThemeResId, @Nullable ColorResources colorResources) { // RemoteViews may be built by an application installed in another // user. So build a context that loads resources from that user but // still returns the current users userId so settings like data / time formats // are loaded without requiring cross user persmissions. final Context contextForResources = getContextForResources(context); + if (colorResources != null) { + colorResources.apply(contextForResources); + } Context inflationContext = new RemoteViewsContextWrapper(context, contextForResources); // If mApplyThemeResId is not given, Theme.DeviceDefault will be used. @@ -4756,34 +4807,37 @@ public class RemoteViews implements Parcelable, Filter { */ public CancellationSignal applyAsync( Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener) { - return applyAsync(context, parent, executor, listener, null); + return applyAsync(context, parent, executor, listener, null /* handler */); } /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler) { - return applyAsync(context, parent, executor, listener, handler, null); + return applyAsync(context, parent, executor, listener, handler, null /* size */); } /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, PointF size) { - return getAsyncApplyTask(context, parent, listener, handler, size).startTaskOnExecutor( - executor); + return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */) + .startTaskOnExecutor(executor); } - private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, - OnViewAppliedListener listener, InteractionHandler handler) { - return getAsyncApplyTask(context, parent, listener, handler, null); + /** @hide */ + public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, + OnViewAppliedListener listener, InteractionHandler handler, PointF size, + ColorResources colorResources) { + return getAsyncApplyTask(context, parent, listener, handler, size, colorResources) + .startTaskOnExecutor(executor); } private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, - OnViewAppliedListener listener, InteractionHandler handler, PointF size) { - return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, - listener, - handler, null); + OnViewAppliedListener listener, InteractionHandler handler, PointF size, + ColorResources colorResources) { + return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener, + handler, colorResources, null /* result */); } private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree> @@ -4794,6 +4848,7 @@ public class RemoteViews implements Parcelable, Filter { final Context mContext; final OnViewAppliedListener mListener; final InteractionHandler mHandler; + final ColorResources mColorResources; private View mResult; private ViewTree mTree; @@ -4802,11 +4857,12 @@ public class RemoteViews implements Parcelable, Filter { private AsyncApplyTask( RemoteViews rv, ViewGroup parent, Context context, OnViewAppliedListener listener, - InteractionHandler handler, View result) { + InteractionHandler handler, ColorResources colorResources, View result) { mRV = rv; mParent = parent; mContext = context; mListener = listener; + mColorResources = colorResources; mHandler = handler; mResult = result; @@ -4816,7 +4872,7 @@ public class RemoteViews implements Parcelable, Filter { protected ViewTree doInBackground(Void... params) { try { if (mResult == null) { - mResult = inflateView(mContext, mRV, mParent); + mResult = inflateView(mContext, mRV, mParent, 0, mColorResources); } mTree = new ViewTree(mResult); @@ -4825,7 +4881,8 @@ public class RemoteViews implements Parcelable, Filter { mActions = new Action[count]; for (int i = 0; i < count && !isCancelled(); i++) { // TODO: check if isCancelled in nested views. - mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler); + mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler, + mColorResources); } } else { mActions = null; @@ -4850,7 +4907,7 @@ public class RemoteViews implements Parcelable, Filter { InteractionHandler handler = mHandler == null ? DEFAULT_INTERACTION_HANDLER : mHandler; for (Action a : mActions) { - a.apply(viewTree.mRoot, mParent, handler); + a.apply(viewTree.mRoot, mParent, handler, mColorResources); } } } catch (Exception e) { @@ -4894,16 +4951,17 @@ public class RemoteViews implements Parcelable, Filter { * the {@link #apply(Context,ViewGroup)} call. */ public void reapply(Context context, View v) { - reapply(context, v, null, null); + reapply(context, v, null /* handler */); } /** @hide */ public void reapply(Context context, View v, InteractionHandler handler) { - reapply(context, v, handler, null); + reapply(context, v, handler, null /* size */, null /* colorResources */); } /** @hide */ - public void reapply(Context context, View v, InteractionHandler handler, PointF size) { + public void reapply(Context context, View v, InteractionHandler handler, PointF size, + ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); // In the case that a view has this RemoteViews applied in one orientation or size, is @@ -4917,7 +4975,7 @@ public class RemoteViews implements Parcelable, Filter { } } - rvToApply.performApply(v, (ViewGroup) v.getParent(), handler); + rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources); } /** @@ -4933,20 +4991,21 @@ public class RemoteViews implements Parcelable, Filter { * @return CancellationSignal * @hide */ - public CancellationSignal reapplyAsync( - Context context, View v, Executor executor, OnViewAppliedListener listener) { - return reapplyAsync(context, v, executor, listener, null, null); + public CancellationSignal reapplyAsync(Context context, View v, Executor executor, + OnViewAppliedListener listener) { + return reapplyAsync(context, v, executor, listener, null); } /** @hide */ public CancellationSignal reapplyAsync(Context context, View v, Executor executor, OnViewAppliedListener listener, InteractionHandler handler) { - return reapplyAsync(context, v, executor, listener, handler, null); + return reapplyAsync(context, v, executor, listener, handler, null, null); } /** @hide */ public CancellationSignal reapplyAsync(Context context, View v, Executor executor, - OnViewAppliedListener listener, InteractionHandler handler, PointF size) { + OnViewAppliedListener listener, InteractionHandler handler, PointF size, + ColorResources colorResources) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); // In the case that a view has this RemoteViews applied in one orientation, is persisted @@ -4960,16 +5019,18 @@ public class RemoteViews implements Parcelable, Filter { } return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), - context, listener, handler, v).startTaskOnExecutor(executor); + context, listener, handler, colorResources, v).startTaskOnExecutor( + executor); } - private void performApply(View v, ViewGroup parent, InteractionHandler handler) { + private void performApply(View v, ViewGroup parent, InteractionHandler handler, + ColorResources colorResources) { if (mActions != null) { handler = handler == null ? DEFAULT_INTERACTION_HANDLER : handler; final int count = mActions.size(); for (int i = 0; i < count; i++) { Action a = mActions.get(i); - a.apply(v, parent, handler); + a.apply(v, parent, handler, colorResources); } } } @@ -5010,6 +5071,122 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Object allowing the modification of a context to overload the system's dynamic colors. + * + * Only colors from {@link android.R.color#system_primary_0} to + * {@link android.R.color#system_neutral_1000} can be overloaded. + * @hide + */ + public static final class ColorResources { + // Set of valid colors resources. + private static final int FIRST_RESOURCE_COLOR_ID = android.R.color.system_primary_0; + private static final int LAST_RESOURCE_COLOR_ID = android.R.color.system_neutral_1000; + // Size, in bytes, of an entry in the array of colors in an ARSC file. + private static final int ARSC_ENTRY_SIZE = 16; + + private ResourcesLoader mLoader; + + private ColorResources(ResourcesLoader loader) { + mLoader = loader; + } + + /** + * Apply the color resources to the given context. + * + * No resource resolution must have be done on the context given to that method. + */ + public void apply(Context context) { + context.getResources().addLoaders(mLoader); + } + + private static ByteArrayOutputStream readFileContent(InputStream input) throws IOException { + ByteArrayOutputStream content = new ByteArrayOutputStream(2048); + byte[] buffer = new byte[4096]; + while (input.available() > 0) { + int read = input.read(buffer); + content.write(buffer, 0, read); + } + return content; + } + + /** + * Creates the compiled resources content from the asset stored in the APK. + * + * The asset is a compiled resource with the correct resources name and correct ids, only + * the values are incorrect. The last value is at the very end of the file. The resources + * are in an array, the array's entries are 16 bytes each. We use this to work out the + * location of all the positions of the various resources. + */ + private static byte[] createCompiledResourcesContent(Context context, + SparseIntArray colorResources) throws IOException { + byte[] content; + try (InputStream input = context.getResources().openRawResource( + com.android.internal.R.raw.remote_views_color_resources)) { + ByteArrayOutputStream rawContent = readFileContent(input); + content = rawContent.toByteArray(); + } + int valuesOffset = + content.length - (LAST_RESOURCE_COLOR_ID & 0xffff) * ARSC_ENTRY_SIZE - 4; + if (valuesOffset < 0) { + Log.e(LOG_TAG, "ARSC file for theme colors is invalid."); + return null; + } + for (int colorRes = FIRST_RESOURCE_COLOR_ID; colorRes <= LAST_RESOURCE_COLOR_ID; + colorRes++) { + // The last 2 bytes are the index in the color array. + int index = colorRes & 0xffff; + int offset = valuesOffset + index * ARSC_ENTRY_SIZE; + int value = colorResources.get(colorRes, context.getColor(colorRes)); + // Write the 32 bit integer in little endian + for (int b = 0; b < 4; b++) { + content[offset + b] = (byte) (value & 0xff); + value >>= 8; + } + } + return content; + } + + /** + * Adds a resource loader for theme colors to the given context. + * + * @param context Context of the view hosting the widget. + * @param colorMapping Mapping of resources to color values. + * + * @hide + */ + public static ColorResources create(Context context, SparseIntArray colorMapping) { + try { + byte[] contentBytes = createCompiledResourcesContent(context, colorMapping); + if (contentBytes == null) { + return null; + } + FileDescriptor arscFile = null; + try { + arscFile = Os.memfd_create("remote_views_theme_colors.arsc", 0 /* flags */); + // Note: This must not be closed through the OutputStream. + try (OutputStream pipeWriter = new FileOutputStream(arscFile)) { + pipeWriter.write(contentBytes); + + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(arscFile)) { + ResourcesLoader colorsLoader = new ResourcesLoader(); + colorsLoader.addProvider(ResourcesProvider + .loadFromTable(pfd, null /* assetsProvider */)); + return new ColorResources(colorsLoader); + } + } + } finally { + if (arscFile != null) { + Os.close(arscFile); + } + } + } catch (Exception ex) { + Log.e(LOG_TAG, "Failed to setup the context for theme colors", ex); + } + return null; + } + } + + /** * Returns the number of actions in this RemoteViews. Can be used as a sequence number. * * @hide |
