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

Commit 99b314af authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fixing indefinite list loading with legacy list conversion" into main

parents ec1e27a4 8006ff70
Loading
Loading
Loading
Loading
+87 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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 android.appwidget;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerWrapper;

import androidx.annotation.Nullable;

/**
 * Activity to proxy config activity launches
 *
 * @hide
 */
public class AppWidgetConfigActivityProxy extends Activity {

    private static final int CONFIG_ACTIVITY_REQUEST_CODE = 1;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setResult(RESULT_CANCELED);
        Intent intent = getIntent();
        Intent target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class);
        if (target == null) {
            finish();
            return;
        }

        startActivityForResult(target, CONFIG_ACTIVITY_REQUEST_CODE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        setResult(resultCode, data);
        int widgetId = getIntent().getIntExtra(
                AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
        AppWidgetManager.getInstance(this).setConfigActivityComplete(widgetId);

        finish();
    }

    @Override
    public WindowManager getWindowManager() {
        return new MyWM(super.getWindowManager());
    }

    /** Wrapper over windowManager with disables adding a window */
    private static class MyWM extends WindowManagerWrapper {

        MyWM(WindowManager original) {
            super(original);
        }

        @Override
        public void addView(View view, ViewGroup.LayoutParams params) { }

        @Override
        public void updateViewLayout(View view, ViewGroup.LayoutParams params) { }

        @Override
        public void removeView(View view) { }

        @Override
        public void removeViewImmediate(View view) { }
    }
}
+159 −55
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.TestApi;
import android.annotation.UiThread;
import android.annotation.UiThread;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.IServiceConnection;
import android.app.IServiceConnection;
import android.app.PendingIntent;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManager;
@@ -47,8 +48,6 @@ import android.os.Binder;
import android.os.Build;
import android.os.Build;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.os.Process;
import android.os.Process;
@@ -57,7 +56,6 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Log;
import android.util.Pair;
import android.widget.RemoteViews;
import android.widget.RemoteViews;


import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.appwidget.IAppWidgetService;
@@ -65,13 +63,14 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.FunctionalUtils;


import java.util.ArrayDeque;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Objects;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Consumer;


/**
/**
@@ -583,6 +582,13 @@ public class AppWidgetManager {
     */
     */
    public static final String EXTRA_APPWIDGET_PREVIEW = "appWidgetPreview";
    public static final String EXTRA_APPWIDGET_PREVIEW = "appWidgetPreview";


    /**
     * The maximum waiting time for remote adapter conversion in milliseconds
     *
     * @hide
     */
    private static final long MAX_ADAPTER_CONVERSION_WAITING_TIME_MS = 20_000;

    /**
    /**
     * Field for the manifest meta-data tag.
     * Field for the manifest meta-data tag.
     *
     *
@@ -600,7 +606,8 @@ public class AppWidgetManager {


    private boolean mHasPostedLegacyLists = false;
    private boolean mHasPostedLegacyLists = false;


    private @NonNull ServiceCollectionCache mServiceCollectionCache;
    @NonNull
    private final ServiceCollectionCache mServiceCollectionCache;


    /**
    /**
     * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
     * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
@@ -653,25 +660,40 @@ public class AppWidgetManager {


    private void tryAdapterConversion(
    private void tryAdapterConversion(
            FunctionalUtils.RemoteExceptionIgnoringConsumer<RemoteViews> action,
            FunctionalUtils.RemoteExceptionIgnoringConsumer<RemoteViews> action,
            RemoteViews original, String failureMsg) {
            RemoteViews original, int[] appWidgetIds, String failureMsg) {
        if (remoteAdapterConversion()
        if (remoteAdapterConversion()) {
                && (mHasPostedLegacyLists = mHasPostedLegacyLists
            mHasPostedLegacyLists = mHasPostedLegacyLists
                        || (original != null && original.hasLegacyLists()))) {
                    || (original != null && original.hasLegacyLists());
        }
        if (remoteAdapterConversion() && mHasPostedLegacyLists && original != null) {
            final RemoteViews viewsCopy = new RemoteViews(original);
            final RemoteViews viewsCopy = new RemoteViews(original);
            Runnable updateWidgetWithTask = () -> {
            Runnable updateWidgetWithTask = () -> {
                try {
                try {
                    viewsCopy.collectAllIntents(mMaxBitmapMemory, mServiceCollectionCache).get();
                    if (shouldSkipListConversion(viewsCopy, appWidgetIds)) {
                        Log.d(TAG, "Skipping legacy list conversion, pending config activity");
                        viewsCopy.replaceAllIntentsWithEmptyList();
                    } else {
                        viewsCopy.collectAllIntents(mMaxBitmapMemory, false /* invalidateData */,
                                        mServiceCollectionCache)
                                .thenRun(() -> {
                                    try {
                                        action.acceptOrThrow(viewsCopy);
                                        action.acceptOrThrow(viewsCopy);
                                    } catch (RemoteException e) {
                                        e.rethrowFromSystemServer();
                                    }
                                }).exceptionally(e -> {
                                    Log.e(TAG, failureMsg, e);
                                    return null;
                                });
                    }
                } catch (Exception e) {
                } catch (Exception e) {
                    Log.e(TAG, failureMsg, e);
                    Log.e(TAG, failureMsg, e);
                }
                }
            };
            };

            if (Looper.getMainLooper() == Looper.myLooper()) {
            if (Looper.getMainLooper() == Looper.myLooper()) {
                createUpdateExecutorIfNull().execute(updateWidgetWithTask);
                createUpdateExecutorIfNull().execute(updateWidgetWithTask);
                return;
                return;
            }
            }

            updateWidgetWithTask.run();
            updateWidgetWithTask.run();
        } else {
        } else {
            try {
            try {
@@ -682,6 +704,13 @@ public class AppWidgetManager {
        }
        }
    }
    }


    private boolean shouldSkipListConversion(RemoteViews views, int[] appWidgetIds)
            throws RemoteException {
        return appWidgetIds.length == 1
                && views.hasLegacyLists()
                && mService.isFirstConfigActivityPending(mPackageName, appWidgetIds[0]);
    }

    /**
    /**
     * Set the RemoteViews to use for the specified appWidgetIds.
     * Set the RemoteViews to use for the specified appWidgetIds.
     * <p>
     * <p>
@@ -707,7 +736,7 @@ public class AppWidgetManager {
        }
        }


        tryAdapterConversion(view -> mService.updateAppWidgetIds(mPackageName, appWidgetIds,
        tryAdapterConversion(view -> mService.updateAppWidgetIds(mPackageName, appWidgetIds,
                view), views, "Error updating app widget views in background");
                view), views, appWidgetIds, "Error updating app widget views in background");
    }
    }


    /**
    /**
@@ -813,7 +842,7 @@ public class AppWidgetManager {
        }
        }


        tryAdapterConversion(view -> mService.partiallyUpdateAppWidgetIds(mPackageName,
        tryAdapterConversion(view -> mService.partiallyUpdateAppWidgetIds(mPackageName,
                appWidgetIds, view), views,
                appWidgetIds, view), views, appWidgetIds,
                "Error partially updating app widget views in background");
                "Error partially updating app widget views in background");
    }
    }


@@ -867,7 +896,7 @@ public class AppWidgetManager {
        }
        }


        tryAdapterConversion(view -> mService.updateAppWidgetProvider(provider, view), views,
        tryAdapterConversion(view -> mService.updateAppWidgetProvider(provider, view), views,
                "Error updating app widget view using provider in background");
                new int[0], "Error updating app widget view using provider in background");
    }
    }


    /**
    /**
@@ -924,10 +953,10 @@ public class AppWidgetManager {
        }
        }


        if (remoteAdapterConversion()) {
        if (remoteAdapterConversion()) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
            mHasPostedLegacyLists = true;
            mHasPostedLegacyLists = true;
                createUpdateExecutorIfNull().execute(() -> notifyCollectionWidgetChange(
            if (Looper.myLooper() == Looper.getMainLooper()) {
                        appWidgetIds, viewId));
                createUpdateExecutorIfNull().execute(
                        () -> notifyCollectionWidgetChange(appWidgetIds, viewId));
            } else {
            } else {
                notifyCollectionWidgetChange(appWidgetIds, viewId);
                notifyCollectionWidgetChange(appWidgetIds, viewId);
            }
            }
@@ -940,23 +969,36 @@ public class AppWidgetManager {
        }
        }
    }
    }


    @WorkerThread
    private void notifyCollectionWidgetChange(int[] appWidgetIds, int viewId) {
    private void notifyCollectionWidgetChange(int[] appWidgetIds, int viewId) {
        try {
        try {
            List<CompletableFuture<Void>> updateFutures = new ArrayList<>();
            for (final int widgetId : appWidgetIds) {
            for (int i = 0; i < appWidgetIds.length; i++) {
                final int widgetId = appWidgetIds[i];
                updateFutures.add(CompletableFuture.runAsync(() -> {
                try {
                try {
                    if (mService.isFirstConfigActivityPending(mPackageName, widgetId)) {
                        Log.d(TAG, "Skipping collection notify, pending config activity");
                        continue;
                    }
                    RemoteViews views = mService.getAppWidgetViews(mPackageName, widgetId);
                    RemoteViews views = mService.getAppWidgetViews(mPackageName, widgetId);
                        if (views.replaceRemoteCollections(viewId)) {
                    if (views == null || !views.replaceRemoteCollections(viewId)) {
                            updateAppWidget(widgetId, views);
                        continue;
                    }
                    }
                    views.collectAllIntents(
                            mMaxBitmapMemory, true /* invalidateData */, mServiceCollectionCache)
                            .thenRun(() -> {
                                try {
                                    mService.updateAppWidgetIds(
                                            mPackageName, new int[]{widgetId}, views);
                                } catch (RemoteException e) {
                                    e.rethrowFromSystemServer();
                                }
                            }).exceptionally(e -> {
                                Log.e(TAG, "Error notifying changes in RemoteViews", e);
                                return null;
                            });
                } catch (Exception e) {
                } catch (Exception e) {
                    Log.e(TAG, "Error notifying changes in RemoteViews", e);
                    Log.e(TAG, "Error notifying changes in RemoteViews", e);
                }
                }
                }));
            }
            }
            CompletableFuture.allOf(updateFutures.toArray(CompletableFuture[]::new)).join();
        } catch (Exception e) {
        } catch (Exception e) {
            Log.e(TAG, "Error notifying changes for all widgets", e);
            Log.e(TAG, "Error notifying changes for all widgets", e);
        }
        }
@@ -1591,20 +1633,29 @@ public class AppWidgetManager {
        }
        }
    }
    }


    /** @hide */
    public void setConfigActivityComplete(int widgetId) {
        try {
            mService.setConfigActivityComplete(widgetId);
        } catch (RemoteException e) {
            Log.d(TAG, "Error notifying config activity completed");
        }
    }

    @UiThread
    @UiThread
    private static @NonNull Executor createUpdateExecutorIfNull() {
    private static @NonNull Executor createUpdateExecutorIfNull() {
        if (sUpdateExecutor == null) {
        if (sUpdateExecutor == null) {
            sUpdateExecutor = new HandlerExecutor(createAndStartNewHandler(
            sUpdateExecutor = createExecutorService(
                    "widget_manager_update_helper_thread", Process.THREAD_PRIORITY_FOREGROUND));
                    "widget_manager_update_helper_thread", Process.THREAD_PRIORITY_FOREGROUND);
        }
        }

        return sUpdateExecutor;
        return sUpdateExecutor;
    }
    }


    private static @NonNull Handler createAndStartNewHandler(@NonNull String name, int priority) {
    private static ExecutorService createExecutorService(@NonNull String name, int priority) {
        HandlerThread thread = new HandlerThread(name, priority);
        return Executors.newSingleThreadExecutor(r -> new Thread(() -> {
        thread.start();
            Process.setThreadPriority(Process.myTid(), priority);
        return thread.getThreadHandler();
            r.run();
        }, name));
    }
    }


    /**
    /**
@@ -1629,27 +1680,31 @@ public class AppWidgetManager {
         * Connect to the service indicated by the {@code Intent}, and consume the binder on the
         * Connect to the service indicated by the {@code Intent}, and consume the binder on the
         * specified executor
         * specified executor
         */
         */
        public void connectAndConsume(Intent intent, Consumer<IBinder> task, Executor executor) {
        public void connectAndConsume(Intent intent, Consumer<IBinder> task) {
            mHandler.post(() -> connectAndConsumeInner(intent, task, executor));
            mHandler.post(() -> connectAndConsumeInner(intent, task));
        }
        }


        private void connectAndConsumeInner(Intent intent, Consumer<IBinder> task,
        private void connectAndConsumeInner(Intent intent, Consumer<IBinder> task) {
                Executor executor) {
            ConnectionTask activeConnection = mActiveConnections.computeIfAbsent(
            ConnectionTask activeConnection = mActiveConnections.computeIfAbsent(
                    new FilterComparison(intent), ConnectionTask::new);
                    new FilterComparison(intent), ConnectionTask::new);
            activeConnection.add(task, executor);
            activeConnection.add(task);
        }
        }


        private class ConnectionTask implements ServiceConnection {
        private class ConnectionTask implements ServiceConnection {


            private final Runnable mDestroyAfterTimeout = this::onDestroyTimeout;
            private final Runnable mDestroyAfterTimeout = this::onDestroyTimeout;
            private final ArrayDeque<Pair<Consumer<IBinder>, Executor>> mTaskQueue =
            private final Runnable mConnectionTimeout = this::onConnectionTimeout;
                    new ArrayDeque<>();
            private final ArrayDeque<Consumer<IBinder>> mTaskQueue = new ArrayDeque<>();


            private final String mExecutorName;
            private boolean mOnDestroyTimeout = false;
            private boolean mOnDestroyTimeout = false;
            private IBinder mIBinder;
            private IBinder mIBinder;


            private ExecutorService mBinderCallExecutor;
            private Object mCurrentTaskToken;

            ConnectionTask(@NonNull FilterComparison filter) {
            ConnectionTask(@NonNull FilterComparison filter) {
                mExecutorName = "appwidget-connectiontask-" + filter.hashCode();
                try {
                try {
                    mContext.bindService(filter.getIntent(),
                    mContext.bindService(filter.getIntent(),
                            Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE),
                            Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE),
@@ -1658,12 +1713,12 @@ public class AppWidgetManager {
                } catch (Exception e) {
                } catch (Exception e) {
                    Log.e(TAG, "Error connecting to service in connection cache", e);
                    Log.e(TAG, "Error connecting to service in connection cache", e);
                }
                }
                mHandler.postDelayed(mConnectionTimeout, MAX_ADAPTER_CONVERSION_WAITING_TIME_MS);
            }
            }


            @Override
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                mIBinder = iBinder;
                onBinderReceived(iBinder);
                mHandler.post(this::handleNext);
            }
            }


            @Override
            @Override
@@ -1672,26 +1727,56 @@ public class AppWidgetManager {
                onServiceConnected(name, new Binder());
                onServiceConnected(name, new Binder());
            }
            }


            private void onConnectionTimeout() {
                onBinderReceived(new Binder());
            }

            private void onBinderReceived(IBinder iBinder) {
                if (mIBinder != null) {
                    return;
                }
                mIBinder = iBinder;
                mHandler.removeCallbacks(mConnectionTimeout);
                mHandler.post(this::handleNext);
            }

            @Override
            @Override
            public void onServiceDisconnected(ComponentName componentName) { }
            public void onServiceDisconnected(ComponentName componentName) { }


            void add(Consumer<IBinder> task, Executor executor) {
            void add(Consumer<IBinder> task) {
                mTaskQueue.add(Pair.create(task, executor));
                mTaskQueue.add(task);
                if (mOnDestroyTimeout) {
                if (mOnDestroyTimeout) {
                    // If we are waiting for timeout, cancel it and execute the next task
                    // If we are waiting for timeout, cancel it and execute the next task
                    handleNext();
                    handleNext();
                }
                }
            }
            }


            private void onTaskComplete(Object taskToken) {
                if (mCurrentTaskToken == taskToken) {
                    mCurrentTaskToken = null;
                    handleNext();
                }
            }

            private void handleNext() {
            private void handleNext() {
                mHandler.removeCallbacks(mDestroyAfterTimeout);
                mHandler.removeCallbacks(mDestroyAfterTimeout);
                Pair<Consumer<IBinder>, Executor> next = mTaskQueue.pollFirst();
                Consumer<IBinder> next = mTaskQueue.pollFirst();
                if (next != null) {
                if (next != null) {
                    mCurrentTaskToken = next;
                    mOnDestroyTimeout = false;
                    mOnDestroyTimeout = false;
                    next.second.execute(() -> {
                    if (mBinderCallExecutor == null) {
                        next.first.accept(mIBinder);
                        mBinderCallExecutor = createExecutorService(
                        mHandler.post(this::handleNext);
                                mExecutorName, Process.THREAD_PRIORITY_FOREGROUND);
                    }
                    Future task = mBinderCallExecutor.submit(() -> {
                        next.accept(mIBinder);
                        mHandler.post(() -> onTaskComplete(next));
                    });
                    });

                    mHandler.postDelayed(
                            () -> onTaskTimeout(task, next),
                            MAX_ADAPTER_CONVERSION_WAITING_TIME_MS);

                } else {
                } else {
                    // Finished all tasks, start a timeout to unbind this service
                    // Finished all tasks, start a timeout to unbind this service
                    mOnDestroyTimeout = true;
                    mOnDestroyTimeout = true;
@@ -1699,6 +1784,22 @@ public class AppWidgetManager {
                }
                }
            }
            }


            /**
             * If a task times out, we try to interrupt it, but also switch to a new executor,
             * in case the previous executor gets blocked for ever
             */
            private void onTaskTimeout(Future task, Object taskToken) {
                if (!task.isDone()) {
                    ExecutorService oldExecutor = mBinderCallExecutor;
                    mBinderCallExecutor = null;
                    task.cancel(true);
                    if (oldExecutor != null) {
                        oldExecutor.shutdown();
                    }
                    onTaskComplete(taskToken);
                }
            }

            /**
            /**
             * Called after we have waited for {@link #mTimeOut} after the last task is finished
             * Called after we have waited for {@link #mTimeOut} after the last task is finished
             */
             */
@@ -1712,6 +1813,9 @@ public class AppWidgetManager {
                } catch (Exception e) {
                } catch (Exception e) {
                    Log.e(TAG, "Error unbinding the cached connection", e);
                    Log.e(TAG, "Error unbinding the cached connection", e);
                }
                }
                if (mBinderCallExecutor != null) {
                    mBinderCallExecutor.shutdown();
                }
                mActiveConnections.values().remove(this);
                mActiveConnections.values().remove(this);
            }
            }
        }
        }
+36 −40

File changed.

Preview size limit exceeded, changes collapsed.

+6 −7
Original line number Original line Diff line number Diff line
@@ -130,8 +130,6 @@ public abstract class RemoteViewsService extends Service {
         */
         */
        default RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize,
        default RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize,
                int capBitmapSize) {
                int capBitmapSize) {
            RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
                    .Builder().build();
            Parcel capSizeTestParcel = Parcel.obtain();
            Parcel capSizeTestParcel = Parcel.obtain();
            // restore allowSquashing to reduce the noise in error messages
            // restore allowSquashing to reduce the noise in error messages
            boolean prevAllowSquashing = capSizeTestParcel.allowSquashing();
            boolean prevAllowSquashing = capSizeTestParcel.allowSquashing();
@@ -140,7 +138,6 @@ public abstract class RemoteViewsService extends Service {
                RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
                RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
                        new RemoteViews.RemoteCollectionItems.Builder();
                        new RemoteViews.RemoteCollectionItems.Builder();
                RemoteViews.BitmapCache testBitmapCache = null;
                RemoteViews.BitmapCache testBitmapCache = null;
                onDataSetChanged();


                itemsBuilder.setHasStableIds(hasStableIds());
                itemsBuilder.setHasStableIds(hasStableIds());
                final int numOfEntries = getCount();
                final int numOfEntries = getCount();
@@ -167,14 +164,12 @@ public abstract class RemoteViewsService extends Service {


                    itemsBuilder.addItem(currentItemId, currentView);
                    itemsBuilder.addItem(currentItemId, currentView);
                }
                }

                return itemsBuilder.build();
                items = itemsBuilder.build();
            } finally {
            } finally {
                capSizeTestParcel.restoreAllowSquashing(prevAllowSquashing);
                capSizeTestParcel.restoreAllowSquashing(prevAllowSquashing);
                // Recycle the parcel
                // Recycle the parcel
                capSizeTestParcel.recycle();
                capSizeTestParcel.recycle();
            }
            }
            return items;
        }
        }
    }
    }


@@ -282,10 +277,14 @@ public abstract class RemoteViewsService extends Service {


        @Override
        @Override
        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize,
        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize,
                int capBitmapSize) {
                int capBitmapSize, boolean invalidateData) {
            RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
            RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
                    .Builder().build();
                    .Builder().build();
            try {
            try {
                if (mIsCreated || invalidateData) {
                    mFactory.onDataSetChanged();
                    mIsCreated = false;
                }
                items = mFactory.getRemoteCollectionItems(capSize, capBitmapSize);
                items = mFactory.getRemoteCollectionItems(capSize, capBitmapSize);
            } catch (Exception ex) {
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread t = Thread.currentThread();
+4 −0
Original line number Original line Diff line number Diff line
@@ -89,5 +89,9 @@ interface IAppWidgetService {
            in ComponentName providerComponent, in int profileId, in int widgetCategory);
            in ComponentName providerComponent, in int profileId, in int widgetCategory);
    void removeWidgetPreview(in ComponentName providerComponent, in int widgetCategories);
    void removeWidgetPreview(in ComponentName providerComponent, in int widgetCategories);
    oneway void reportWidgetEvents(in String callingPackage, in AppWidgetEvent[] events);
    oneway void reportWidgetEvents(in String callingPackage, in AppWidgetEvent[] events);

    // For legacy list migration
    boolean isFirstConfigActivityPending(in String callingPackage, in int appWidgetId);
    oneway void setConfigActivityComplete(in int appWidgetId);
}
}
Loading