1742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani/*
2742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * Copyright (C) 2011 The Android Open Source Project
3742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *
4742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * Licensed under the Apache License, Version 2.0 (the "License");
5742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * you may not use this file except in compliance with the License.
6742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * You may obtain a copy of the License at
7742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *
8742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *      http://www.apache.org/licenses/LICENSE-2.0
9742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *
10742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * Unless required by applicable law or agreed to in writing, software
11742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * distributed under the License is distributed on an "AS IS" BASIS,
12742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * See the License for the specific language governing permissions and
14742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * limitations under the License.
15742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani */
16742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1730f8eb472e44228069c2ffb8bd0b43213edbf04eAmith Yamasanipackage com.android.server.appwidget;
18742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
19742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.app.AlarmManager;
20483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasaniimport android.app.AppGlobals;
215771ad7bc7533f4a9bc72ac1ecabfdf6ca493b16Svet Ganovimport android.app.AppOpsManager;
22742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.app.PendingIntent;
23976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.app.admin.DevicePolicyManagerInternal;
246bd702538d90005add1cfc33746da19404090dc1Svet Ganovimport android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
25742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.appwidget.AppWidgetManager;
26742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.appwidget.AppWidgetProviderInfo;
27976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.BroadcastReceiver;
28742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.ComponentName;
29742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.Context;
30742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.Intent;
31742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.Intent.FilterComparison;
32976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.IntentFilter;
33976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.IntentSender;
3461a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurkaimport android.content.ServiceConnection;
35742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ActivityInfo;
36742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ApplicationInfo;
37483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasaniimport android.content.pm.IPackageManager;
38742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.PackageInfo;
39742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.PackageManager;
40742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ResolveInfo;
41742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ServiceInfo;
42976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.pm.UserInfo;
43742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.res.Resources;
44742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.res.TypedArray;
45742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.res.XmlResourceParser;
46a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brownimport android.graphics.Point;
47742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.net.Uri;
48742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.Binder;
49742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.Bundle;
5061f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasaniimport android.os.Environment;
51a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohenimport android.os.Handler;
52742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.IBinder;
53976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.os.Looper;
54976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.os.Message;
55f229e4d3eb8f910c181f96416c6798f6f305a395Jim Millerimport android.os.Process;
56742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.RemoteException;
57742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.SystemClock;
58f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
59976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.os.UserManager;
60976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.text.TextUtils;
61976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.util.ArraySet;
6239606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile;
63742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.AttributeSet;
64742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.Pair;
65742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.Slog;
66976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.util.SparseIntArray;
67742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.TypedValue;
68742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.Xml;
69a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brownimport android.view.Display;
70311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohenimport android.view.WindowManager;
71742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.widget.RemoteViews;
72742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
73742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.appwidget.IAppWidgetHost;
74976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.internal.appwidget.IAppWidgetService;
75976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.internal.os.BackgroundThread;
76976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.internal.os.SomeArgs;
77742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.util.FastXmlSerializer;
78742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.widget.IRemoteViewsAdapterConnection;
79742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.widget.IRemoteViewsFactory;
80742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
81976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.server.LocalServices;
82976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.server.WidgetBackupProvider;
83976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport libcore.io.IoUtils;
84742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport org.xmlpull.v1.XmlPullParser;
85742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport org.xmlpull.v1.XmlPullParserException;
86742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport org.xmlpull.v1.XmlSerializer;
87742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
88adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.io.ByteArrayInputStream;
89adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.io.ByteArrayOutputStream;
90742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.File;
91742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileDescriptor;
92742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileInputStream;
93742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileNotFoundException;
94742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileOutputStream;
95742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.IOException;
96742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.PrintWriter;
97742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.ArrayList;
98976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport java.util.Collections;
99742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.HashMap;
100742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.HashSet;
101742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.Iterator;
102742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.List;
103742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.Locale;
104976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport java.util.Map;
105742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.Set;
106742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1076bd702538d90005add1cfc33746da19404090dc1Svet Ganovclass AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
1086bd702538d90005add1cfc33746da19404090dc1Svet Ganov        OnCrossProfileWidgetProvidersChangeListener {
109976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String TAG = "AppWidgetServiceImpl";
110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
111976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static boolean DEBUG = false;
112742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
113976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String OLD_KEYGUARD_HOST_PACKAGE = "android";
114976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard";
11539d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller    private static final int KEYGUARD_HOST_ID = 0x4b455947;
116742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
117976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String STATE_FILENAME = "appwidgets.xml";
1188320de8e29819963845d3d386d6d087844a5ae31Amith Yamasani
119976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int MIN_UPDATE_PERIOD = DEBUG ? 0 : 30 * 60 * 1000; // 30 minutes
120742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
121976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int TAG_UNDEFINED = -1;
122742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
123976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int UNKNOWN_UID = -1;
124adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
125976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int LOADED_PROFILE_ID = -1;
126adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
127976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int UNKNOWN_USER_ID = -10;
128742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
129976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Bump if the stored widgets need to be upgraded.
130976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int CURRENT_VERSION = 1;
131c566b43d02596cba437e9a2723e9f989297cca72Amith Yamasani
132976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
133976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void onReceive(Context context, Intent intent) {
134976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String action = intent.getAction();
135adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
136976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
137976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Received broadcast: " + action);
138adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
139adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
141976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onConfigurationChanged();
142976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (Intent.ACTION_USER_STARTED.equals(action)) {
143976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onUserStarted(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        UserHandle.USER_NULL));
145976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
146976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onUserStopped(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
147976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        UserHandle.USER_NULL));
148976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
149976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onPackageBroadcastReceived(intent, intent.getIntExtra(
150976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL));
151976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
152adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
153976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    };
154742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
155976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Manages active connections to RemoteViewsServices.
156976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
157976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mBoundRemoteViewsServices = new HashMap<>();
158adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
159976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Manages persistent references to RemoteViewsServices from different App Widgets.
160976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final HashMap<Pair<Integer, FilterComparison>, HashSet<Integer>>
161976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mRemoteViewsServicesAppWidgets = new HashMap<>();
162adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
163976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final Object mLock = new Object();
164adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
165976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArrayList<Widget> mWidgets = new ArrayList<>();
166976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArrayList<Host> mHosts = new ArrayList<>();
167976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArrayList<Provider> mProviders = new ArrayList<>();
168adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
169976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArraySet<Pair<Integer, String>> mPackagesWithBindWidgetPermission =
170976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            new ArraySet<>();
171742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
172976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final SparseIntArray mLoadedUserIds = new SparseIntArray();
173742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
174976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final BackupRestoreController mBackupRestoreController;
175742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
176976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final Context mContext;
177742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
178976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final IPackageManager mPackageManager;
179976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final AlarmManager mAlarmManager;
180976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final UserManager mUserManager;
1815771ad7bc7533f4a9bc72ac1ecabfdf6ca493b16Svet Ganov    private final AppOpsManager mAppOpsManager;
182742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
183976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final SecurityPolicy mSecurityPolicy;
184adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
185a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen    private final Handler mSaveStateHandler;
186976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final Handler mCallbackHandler;
187a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen
188976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Locale mLocale;
189742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
190976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final SparseIntArray mNextAppWidgetIds = new SparseIntArray();
191976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
192976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean mSafeMode;
193976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int mMaxWidgetBitmapMemory;
194976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
195976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    AppWidgetServiceImpl(Context context) {
196742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        mContext = context;
197976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mPackageManager = AppGlobals.getPackageManager();
198742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
199976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
2005771ad7bc7533f4a9bc72ac1ecabfdf6ca493b16Svet Ganov        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
201976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSaveStateHandler = BackgroundThread.getHandler();
202976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
203976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController = new BackupRestoreController();
204976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy = new SecurityPolicy();
205311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen        computeMaximumWidgetBitmapMemory();
206976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        registerBroadcastReceiver();
2076bd702538d90005add1cfc33746da19404090dc1Svet Ganov        registerOnCrossProfileProvidersChangedListener();
208311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen    }
209311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen
210976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void computeMaximumWidgetBitmapMemory() {
211311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
212a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        Display display = wm.getDefaultDisplay();
213a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        Point size = new Point();
214a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        display.getRealSize(size);
215e92aad432add317793a69a34eab5d271962df220Winson Chung        // Cap memory usage at 1.5 times the size of the display
216e92aad432add317793a69a34eab5d271962df220Winson Chung        // 1.5 * 4 bytes/pixel * w * h ==> 6 * w * h
217a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        mMaxWidgetBitmapMemory = 6 * size.x * size.y;
218742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
219742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
220976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void registerBroadcastReceiver() {
221976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Register for configuration changes so we can update the names
222976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // of the widgets when the locale changes.
223976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter configFilter = new IntentFilter();
224976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        configFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
225976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
226976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                configFilter, null, null);
227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Register for broadcasts about package install, etc., so we can
229976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // update the provider list.
230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter packageFilter = new IntentFilter();
231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
232976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addDataScheme("package");
235976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
236976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                packageFilter, null, null);
237976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
238976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Register for events related to sdcard installation.
239976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter sdFilter = new IntentFilter();
240976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
241976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
242976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sdFilter, null, null);
244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
245976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter userFilter = new IntentFilter();
246976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        userFilter.addAction(Intent.ACTION_USER_STARTED);
247976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        userFilter.addAction(Intent.ACTION_USER_STOPPED);
248976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
249976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                userFilter, null, null);
250976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
251976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2526bd702538d90005add1cfc33746da19404090dc1Svet Ganov    private void registerOnCrossProfileProvidersChangedListener() {
2536bd702538d90005add1cfc33746da19404090dc1Svet Ganov        DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
2546bd702538d90005add1cfc33746da19404090dc1Svet Ganov                DevicePolicyManagerInternal.class);
2556bd702538d90005add1cfc33746da19404090dc1Svet Ganov        // The device policy is an optional component.
2566bd702538d90005add1cfc33746da19404090dc1Svet Ganov        if (devicePolicyManager != null) {
2576bd702538d90005add1cfc33746da19404090dc1Svet Ganov            devicePolicyManager.addOnCrossProfileWidgetProvidersChangeListener(this);
2586bd702538d90005add1cfc33746da19404090dc1Svet Ganov        }
2596bd702538d90005add1cfc33746da19404090dc1Svet Ganov    }
2606bd702538d90005add1cfc33746da19404090dc1Svet Ganov
261976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void setSafeMode(boolean safeMode) {
262742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        mSafeMode = safeMode;
263742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
264742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
265976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onConfigurationChanged() {
266976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "onConfigurationChanged()");
268976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2698320de8e29819963845d3d386d6d087844a5ae31Amith Yamasani
270742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        Locale revised = Locale.getDefault();
271976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (revised == null || mLocale == null || !revised.equals(mLocale)) {
272742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            mLocale = revised;
273742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
274976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
275976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                SparseIntArray changedGroups = null;
276976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
277a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the
278a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                // list of installed providers and skip providers that we don't need to update.
279a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                // Also note that remove the provider does not clear the Provider component data.
280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ArrayList<Provider> installedProviders = new ArrayList<>(mProviders);
281976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                HashSet<ProviderId> removedProviders = new HashSet<>();
282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
283a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                int N = installedProviders.size();
284742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                for (int i = N - 1; i >= 0; i--) {
285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = installedProviders.get(i);
286976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
287976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ensureGroupStateLoadedLocked(provider.getUserId());
288976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
289976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (!removedProviders.contains(provider.id)) {
290976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final boolean changed = updateProvidersForPackageLocked(
291976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                provider.id.componentName.getPackageName(),
292976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                provider.getUserId(), removedProviders);
293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (changed) {
295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            if (changedGroups == null) {
296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                changedGroups = new SparseIntArray();
297976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
298976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int groupId = mSecurityPolicy.getGroupParent(
299976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    provider.getUserId());
300976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            changedGroups.put(groupId, groupId);
301976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
302976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
303976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
304976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
305976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (changedGroups != null) {
306976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int groupCount = changedGroups.size();
307976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < groupCount; i++) {
308976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int groupId = changedGroups.get(i);
309976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        saveGroupStateAsync(groupId);
310a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                    }
311742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
312742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
313742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
314742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
315742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
316976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onPackageBroadcastReceived(Intent intent, int userId) {
317742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        final String action = intent.getAction();
318742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        boolean added = false;
319742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        boolean changed = false;
320976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean componentsModified = false;
321976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
322742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        String pkgList[] = null;
323742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
324742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
325742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            added = true;
326742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
327742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
328742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            added = false;
329742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } else {
330742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Uri uri = intent.getData();
331742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (uri == null) {
332742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return;
333742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
334742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            String pkgName = uri.getSchemeSpecificPart();
335742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (pkgName == null) {
336742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return;
337742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
338742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pkgList = new String[] { pkgName };
339742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            added = Intent.ACTION_PACKAGE_ADDED.equals(action);
340742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
341742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
342742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        if (pkgList == null || pkgList.length == 0) {
343742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return;
344742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Bundle extras = intent.getExtras();
350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (added || changed) {
352976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean newPackageAdded = added && (extras == null
353976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        || !extras.getBoolean(Intent.EXTRA_REPLACING, false));
354976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
355976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (String pkgName : pkgList) {
356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // Fix up the providers - add/remove/update.
357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    componentsModified |= updateProvidersForPackageLocked(pkgName, userId, null);
358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
359976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // ... and see if these are hosts we've been awaiting.
360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // NOTE: We are backing up and restoring only the owner.
361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (newPackageAdded && userId == UserHandle.USER_OWNER) {
362976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(pkgName, userId);
363976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid >= 0 ) {
364976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            resolveHostUidLocked(pkgName, uid);
365adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                        }
366adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                    }
367742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
368742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } else {
369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If the package is being updated, we'll receive a PACKAGE_ADDED
370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // shortly, otherwise it is removed permanently.
371976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean packageRemovedPermanently = (extras == null
372976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        || !extras.getBoolean(Intent.EXTRA_REPLACING, false));
373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
374976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageRemovedPermanently) {
375742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    for (String pkgName : pkgList) {
376976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        componentsModified |= removeHostsAndProvidersForPackageLocked(
377976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                pkgName, userId);
378742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
379742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
380742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
3817fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
382976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (componentsModified) {
383976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveGroupStateAsync(userId);
384976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
385976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If the set of providers has been modified, notify each active AppWidgetHost
3866bd702538d90005add1cfc33746da19404090dc1Svet Ganov                scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
3877fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung            }
3887fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        }
389742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
390742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
391976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void resolveHostUidLocked(String pkg, int uid) {
392adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        final int N = mHosts.size();
393adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        for (int i = 0; i < N; i++) {
394976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
395976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host.id.uid == UNKNOWN_UID && pkg.equals(host.id.packageName)) {
396976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (DEBUG) {
397976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.i(TAG, "host " + host.id + " resolved to uid " + uid);
398adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
399976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.id = new HostId(uid, host.id.hostId, host.id.packageName);
400976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return;
401adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
402adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
403adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
404adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
405976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void ensureGroupStateLoadedLocked(int userId) {
406976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
407742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
408976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Careful lad, we may have already loaded the state for some
409976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // group members, so check before loading and read only the
410976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // state for the new member(s).
411976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int newMemberCount = 0;
412976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileIdCount = profileIds.length;
413976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileIdCount; i++) {
414976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
415976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mLoadedUserIds.indexOfKey(profileId) >= 0) {
416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                profileIds[i] = LOADED_PROFILE_ID;
417976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
418976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newMemberCount++;
419976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
420742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
421976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
422976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (newMemberCount <= 0) {
423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
424742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
426976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int newMemberIndex = 0;
427976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int[] newProfileIds = new int[newMemberCount];
428976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileIdCount; i++) {
429976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
430976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (profileId != LOADED_PROFILE_ID) {
431976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mLoadedUserIds.put(profileId, profileId);
432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newProfileIds[newMemberIndex] = profileId;
433976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newMemberIndex++;
434976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
435742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
436976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
437c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav        clearProvidersAndHostsTagsLocked();
438c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav
439976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        loadGroupWidgetProvidersLocked(newProfileIds);
440976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        loadGroupStateLocked(newProfileIds);
441742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
442742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
443976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
444976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
44575d8c0b8bc28f61658c62b870ae8705e0be191cbNick Kralevich        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
44675d8c0b8bc28f61658c62b870ae8705e0be191cbNick Kralevich                                                "Permission Denial: can't dump from from pid="
44775d8c0b8bc28f61658c62b870ae8705e0be191cbNick Kralevich                                                + Binder.getCallingPid()
44875d8c0b8bc28f61658c62b870ae8705e0be191cbNick Kralevich                                                + ", uid=" + Binder.getCallingUid());
449742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
450976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
451976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int N = mProviders.size();
452742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println("Providers:");
453976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
454976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                dumpProvider(mProviders.get(i), i, pw);
455742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
456742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
457976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mWidgets.size();
458742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println(" ");
459976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.println("Widgets:");
460976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
461976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                dumpWidget(mWidgets.get(i), i, pw);
462742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
463742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
464742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            N = mHosts.size();
465742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println(" ");
466742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println("Hosts:");
467976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
468742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                dumpHost(mHosts.get(i), i, pw);
469742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
470742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
471742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
472976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mPackagesWithBindWidgetPermission.size();
473742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println(" ");
474976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.println("Grants:");
475976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
476976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> grant = mPackagesWithBindWidgetPermission.valueAt(i);
477976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                dumpGrant(grant, i, pw);
478742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
479742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
480742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
481742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
482976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
483976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int[] startListening(IAppWidgetHost callbacks, String callingPackage,
484976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int hostId, List<RemoteViews> updatedViews) {
485976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
486976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
487976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
488976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "startListening() " + userId);
489742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
490742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
491976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
492976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
493742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
494976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
495976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
496742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
497976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
498976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts it owns.
499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
500976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupOrAddHostLocked(id);
501742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
502976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            host.callbacks = callbacks;
503742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
504976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            updatedViews.clear();
505742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<Widget> instances = host.widgets;
507976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int N = instances.size();
508976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int[] updatedIds = new int[N];
509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
510976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = instances.get(i);
511976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                updatedIds[i] = widget.appWidgetId;
512976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                updatedViews.add(cloneIfLocalBinder(widget.views));
513742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return updatedIds;
516742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
517742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
518742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void stopListening(String callingPackage, int hostId) {
521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
524976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "stopListening() " + userId);
525742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
526742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
527976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
528976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
529976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
530976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
531976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
533976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
534976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts it owns.
535976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
536976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(id);
537976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
538976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
539976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                pruneHostLocked(host);
541742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
542742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
543742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
544742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
545976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
546976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int allocateAppWidgetId(String callingPackage, int hostId) {
547976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
548976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
549976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
550976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "allocateAppWidgetId() " + userId);
551742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
552742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
554976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
555742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
556976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
557976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
558742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
559976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mNextAppWidgetIds.indexOfKey(userId) < 0) {
560976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mNextAppWidgetIds.put(userId, AppWidgetManager.INVALID_APPWIDGET_ID + 1);
561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
562742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
563976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int appWidgetId = incrementAndGetAppWidgetIdLocked(userId);
564742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
565976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
566976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts it owns.
567976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
568976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupOrAddHostLocked(id);
569976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
570976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = new Widget();
571976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.appWidgetId = appWidgetId;
572976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host = host;
573976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
574976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            host.widgets.add(widget);
575976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.add(widget);
576976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
577976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
578976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
579976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
580976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Allocated widget id " + appWidgetId
581976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for host " + host.id);
582742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
583976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
584976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return appWidgetId;
585742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
586742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
587742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
588976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
589976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void deleteAppWidgetId(String callingPackage, int appWidgetId) {
590976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
591976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
592976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
593976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "deleteAppWidgetId() " + userId);
594742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
595742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
596976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
597976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
598742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
599976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
600976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
6010aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
602976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
604976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
605976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
6060aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
607976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
608976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return;
609976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
610742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            deleteAppWidgetLocked(widget);
612742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
613976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
614976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
615976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
616976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Deleted widget id " + appWidgetId
617976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for host " + widget.host.id);
618742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
619742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
620742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
621742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
622976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public boolean hasBindAppWidgetPermission(String packageName, int grantId) {
624976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
625976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "hasBindAppWidgetPermission() " + UserHandle.getCallingUserId());
626119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
627976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
628976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // A special permission is required for managing white listing.
629976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName);
630976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
631976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
632976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // The grants are stored in user state wich gets the grant.
633976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(grantId);
634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int packageUid = getUidForPackage(packageName, grantId);
636976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageUid < 0) {
63761a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                return false;
63861a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka            }
639976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
640976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, String> packageId = Pair.create(grantId, packageName);
641976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return mPackagesWithBindWidgetPermission.contains(packageId);
64261a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
64361a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka    }
64461a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
645976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
646976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void setBindAppWidgetPermission(String packageName, int grantId,
647976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean grantPermission) {
648976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
649976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "setBindAppWidgetPermission() " + UserHandle.getCallingUserId());
65061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
651976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
652976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // A special permission is required for managing white listing.
653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName);
654976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
655976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
656976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // The grants are stored in user state wich gets the grant.
657976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(grantId);
658976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
659976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int packageUid = getUidForPackage(packageName, grantId);
660976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageUid < 0) {
661976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return;
662976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
663976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
664976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, String> packageId = Pair.create(grantId, packageName);
665976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (grantPermission) {
666976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPackagesWithBindWidgetPermission.add(packageId);
667976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
668976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPackagesWithBindWidgetPermission.remove(packageId);
669976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
670976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
671976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(grantId);
67261a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
67361a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka    }
67461a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
675976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
6768e1d299da27da534b508b1da51ebe351a689cefaSvetoslav    public IntentSender createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId,
6778e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            int intentFlags) {
678976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
679976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
680976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
681976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "createAppWidgetConfigIntentSender() " + userId);
682119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
68361a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
684976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
685976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
686976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
687976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
688976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
689976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
690976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
691976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
692976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
693976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
694976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
695976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
696976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("Bad widget id " + appWidgetId);
697742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
698976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = widget.provider;
700976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider == null) {
701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("Widget not bound " + appWidgetId);
702742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
703742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
7048e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
7058e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
7068e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            intent.setComponent(provider.info.configure);
7078e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            intent.setFlags(intentFlags);
7081c5bffbf5bae6762c8df07350abca61e460653bbAdam Cohen
709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // All right, create the sender.
710976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
711742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            try {
712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return PendingIntent.getActivityAsUser(
713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
7148e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                                | PendingIntent.FLAG_CANCEL_CURRENT, null,
7158e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                                new UserHandle(provider.getUserId()))
716976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        .getIntentSender();
717742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } finally {
718976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
719742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
720742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
721742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
722742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public boolean bindAppWidgetId(String callingPackage, int appWidgetId,
725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int providerProfileId, ComponentName providerComponent, Bundle options) {
726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
729976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "bindAppWidgetId() " + userId);
730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
731976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
732976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
733976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
734976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
735976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Check that if a cross-profile binding is attempted, it is allowed.
7368e1d299da27da534b508b1da51ebe351a689cefaSvetoslav        if (!mSecurityPolicy.isEnabledGroupProfile(providerProfileId)) {
737976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
738976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
739976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
740976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // If the provider is not under the calling user, make sure this
741976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // provider is white listed for access from the parent.
742976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed(
743976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                providerComponent.getPackageName(), providerProfileId)) {
744976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
745976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
746976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
747976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
748976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
749976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
750976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // A special permission or white listing is required to bind widgets.
751976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!mSecurityPolicy.hasCallerBindPermissionOrBindWhiteListedLocked(
752976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    callingPackage)) {
753976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
754119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
755742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
756976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
757976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
758976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
759976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
760976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
761976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
762976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Bad widget id " + appWidgetId);
763976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
764742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
765742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
766976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.provider != null) {
767976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget id " + appWidgetId
768976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " already bound to: " + widget.provider.id);
769976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
770742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
771742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
772976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerUid = getUidForPackage(providerComponent.getPackageName(),
773976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    providerProfileId);
774976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (providerUid < 0) {
775976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Package " + providerComponent.getPackageName() + " not installed "
776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for profile " + providerProfileId);
777976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
778976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
779742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
780976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
781976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the provider is in the already vetted user profile.
782976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId providerId = new ProviderId(providerUid, providerComponent);
783976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = lookupProviderLocked(providerId);
784976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
785976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider == null) {
786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "No widget provider " + providerComponent + " for profile "
787976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + providerProfileId);
788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
789742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
790742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
791976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider.zombie) {
792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Can't bind to a 3rd party provider in"
793976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " safe mode " + provider);
794976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
795742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
796742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
797976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider = provider;
798976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
799976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
800976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // We need to provide a default value for the widget category if it is not specified
801976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
802976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
803976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
804976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
805976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
806976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.widgets.add(widget);
807976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
808976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int widgetCount = provider.widgets.size();
809976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widgetCount == 1) {
810976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Tell the provider that it's ready.
811976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendEnableIntentLocked(provider);
812976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
813976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
814976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Send an update now -- We need this update now, and just for this appWidgetId.
815976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // It's less critical when the next one happens, so when we schedule the next one,
816976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we add updatePeriodMillis to its start time. That time will have some slop,
817976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // but that's okay.
818976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            sendUpdateIntentLocked(provider, new int[] {appWidgetId});
819976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
820976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Schedule the future updates.
821976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            registerForBroadcastsLocked(provider, getWidgetIds(provider.widgets));
822976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
823976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
824976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
825976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
826976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Bound widget " + appWidgetId + " to provider " + provider.id);
827976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
828742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
829976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
830976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return true;
831742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
832742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
833976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
834976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int[] getAppWidgetIds(ComponentName componentName) {
835976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
836976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
837976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
838976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetIds() " + userId);
839742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
840742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
841976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
842976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
843976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
844976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
845976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
846976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
847976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
848976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can access only its providers.
849976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
850976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = lookupProviderLocked(providerId);
851976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
852976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider != null) {
853976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return getWidgetIds(provider.widgets);
854742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
855976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
856976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return new int[0];
857742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
858742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
859742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
860976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
861976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int[] getAppWidgetIdsForHost(String callingPackage, int hostId) {
862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
863976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
864976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
865976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetIdsForHost() " + userId);
866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
867976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
868976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
871976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
872976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
873976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
874976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
875976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access its hosts.
876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
877976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(id);
878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
879976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
880976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return getWidgetIds(host.widgets);
881742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
882976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
883976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return new int[0];
884742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
885742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
886742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
887976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void bindRemoteViewsService(String callingPackage, int appWidgetId,
889976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Intent intent, IBinder callbacks) {
890976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
893976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "bindRemoteViewsService() " + userId);
894976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
895976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
8965771ad7bc7533f4a9bc72ac1ecabfdf6ca493b16Svet Ganov        // Make sure the package runs under the caller uid.
8975771ad7bc7533f4a9bc72ac1ecabfdf6ca493b16Svet Ganov        mSecurityPolicy.enforceCallFromPackage(callingPackage);
8985771ad7bc7533f4a9bc72ac1ecabfdf6ca493b16Svet Ganov
899976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
906976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("Bad widget id");
909119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
911976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Make sure the widget has a provider.
912976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.provider == null) {
913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("No provider for widget "
914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + appWidgetId);
915742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
916742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ComponentName componentName = intent.getComponent();
918976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
919976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Ensure that the service belongs to the same package as the provider.
920976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // But this is not enough as they may be under different users - see below...
921976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String providerPackage = widget.provider.id.componentName.getPackageName();
922976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String servicePackage = componentName.getPackageName();
923976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!servicePackage.equals(providerPackage)) {
924976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new SecurityException("The taget service not in the same package"
925976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " as the widget provider");
926119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
927976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
928976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Make sure this service exists under the same user as the provider and
929976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // requires a permission which allows only the system to bind to it.
930976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mSecurityPolicy.enforceServiceExistsAndRequiresBindRemoteViewsPermission(
931976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    componentName, widget.provider.getUserId());
932976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
933976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Good to go - the service pakcage is correct, it exists for the correct
934976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // user, and requires the bind permission.
935976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
936976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If there is already a connection made for this service intent, then
937976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // disconnect from that first. (This does not allow multiple connections
938976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // to the same service under the same key).
939976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ServiceConnectionProxy connection = null;
940976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            FilterComparison fc = new FilterComparison(intent);
941976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
942976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
943976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mBoundRemoteViewsServices.containsKey(key)) {
944976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                connection = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                connection.disconnect();
946976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                unbindService(connection);
947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mBoundRemoteViewsServices.remove(key);
948742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
950976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Bind to the RemoteViewsService (which will trigger a callback to the
951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // RemoteViewsAdapter.onServiceConnected())
952976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            connection = new ServiceConnectionProxy(callbacks);
953976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            bindService(intent, connection, widget.provider.info.getProfile());
954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mBoundRemoteViewsServices.put(key, connection);
955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Add it to the mapping of RemoteViewsService to appWidgetIds so that we
957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // can determine when we can call back to the RemoteViewsService later to
958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // destroy associated factories.
959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> serviceId = Pair.create(widget.provider.id.uid, fc);
960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            incrementAppWidgetServiceRefCount(appWidgetId, serviceId);
961742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
962742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
963742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void unbindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent) {
966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
967311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen
968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "unbindRemoteViewsService() " + userId);
970742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
971742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
972976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
973976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Unbind from the RemoteViewsService (which will trigger a callback to the bound
979976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // RemoteViewsAdapter)
980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
981976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    new FilterComparison(intent));
982976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mBoundRemoteViewsServices.containsKey(key)) {
983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // We don't need to use the appWidgetId until after we are sure there is something
984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // to unbind. Note that this may mask certain issues with apps calling unbind()
985976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // more than necessary.
986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // NOTE: The lookup is enforcing security across users by making
988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // sure the caller can only access widgets it hosts or provides.
989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = lookupWidgetLocked(appWidgetId,
990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Binder.getCallingUid(), callingPackage);
991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget == null) {
993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new IllegalArgumentException("Bad widget id " + appWidgetId);
994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ServiceConnectionProxy connection = (ServiceConnectionProxy)
997976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mBoundRemoteViewsServices.get(key);
998976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                connection.disconnect();
999976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.unbindService(connection);
1000976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mBoundRemoteViewsServices.remove(key);
1001742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1002742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1003742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1004742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1005976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void deleteHost(String callingPackage, int hostId) {
1007976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1008a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen
1009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "deleteHost() " + userId);
1011a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen        }
1012a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen
1013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts in its uid and package.
1021976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(id);
1023e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host == null) {
1025e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen                return;
1026e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen            }
10270aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
1028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            deleteHostLocked(host);
1029e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
1031e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
1033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Deleted host " + host.id);
1034e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen            }
1035e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen        }
1036e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen    }
1037e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1038976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1039976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void deleteAllHosts() {
1040976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1041976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "deleteAllHosts() " + userId);
1044742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1045742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1048976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1049976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean changed = false;
1050976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mHosts.size();
1052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = N - 1; i >= 0; i--) {
1053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Host host = mHosts.get(i);
1054976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Delete only hosts in the calling uid.
1056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (host.id.uid == Binder.getCallingUid()) {
1057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    deleteHostLocked(host);
1058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    changed = true;
1059976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1060976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
1061976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "Deleted host " + host.id);
1062976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
10636611988429d1d70ec429f87bbf2b093cf1e2e31fWinson Chung                }
1064742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1065976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1066976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (changed) {
1067976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveGroupStateAsync(userId);
1068976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1069742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1070742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1071742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1072976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1073976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public AppWidgetProviderInfo getAppWidgetInfo(String callingPackage, int appWidgetId) {
1074976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1075976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1076976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1077976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetInfo() " + userId);
1078119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
1079976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1080976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1081976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1082976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1083976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1084976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1085976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1086976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1087976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1088976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1089976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1090976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1091976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget != null && widget.provider != null && !widget.provider.zombie) {
1092976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return cloneIfLocalBinder(widget.provider.info);
1093976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1094976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1095976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
1096742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1097976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1098976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1099976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1100976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public RemoteViews getAppWidgetViews(String callingPackage, int appWidgetId) {
1101976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1102976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1103976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1104976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetViews() " + userId);
1105742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1106742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1107976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1108976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1109976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1111976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1112976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1113976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1114976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1115976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1116976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1117976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1118976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget != null) {
1119976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return cloneIfLocalBinder(widget.views);
1120742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1121976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1122976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
1123742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1124742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1125742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1126976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1127976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void updateAppWidgetOptions(String callingPackage, int appWidgetId, Bundle options) {
1128976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1129976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1130976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1131976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "updateAppWidgetOptions() " + userId);
1132119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
1133976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1134976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1135976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1136976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1137976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1138976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1139976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1141976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1142976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1143976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1145976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
1146742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return;
1147742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1148976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1149976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Merge the options.
1150976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.options.putAll(options);
1151976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1152976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Send the broacast to notify the provider that options changed.
1153976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            sendOptionsChangedIntentLocked(widget);
1154976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1155976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
1156742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1157742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1158742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1159976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1160976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public Bundle getAppWidgetOptions(String callingPackage, int appWidgetId) {
1161976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1162742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1163976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1164976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetOptions() " + userId);
1165976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1166742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1167976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1168976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1169742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1170976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1171976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1172976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1173976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1174976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1175976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1176976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1177976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1178976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget != null && widget.options != null) {
1179976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return cloneIfLocalBinder(widget.options);
1180742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1181976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1182976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return Bundle.EMPTY;
1183742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1184742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1185742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1186976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1187976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void updateAppWidgetIds(String callingPackage, int[] appWidgetIds,
1188976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            RemoteViews views) {
1189976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1190976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "updateAppWidgetIds() " + UserHandle.getCallingUserId());
1191976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1192742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1193976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        updateAppWidgetIds(callingPackage, appWidgetIds, views, false);
1194976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1195742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1196976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1197976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void partiallyUpdateAppWidgetIds(String callingPackage, int[] appWidgetIds,
1198976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            RemoteViews views) {
1199976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1200976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "partiallyUpdateAppWidgetIds() " + UserHandle.getCallingUserId());
1201742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1202742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1203976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        updateAppWidgetIds(callingPackage, appWidgetIds, views, true);
12043ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen    }
12053ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1206976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1207976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds,
1208976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int viewId) {
1209976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
12103ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1211976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1212976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "notifyAppWidgetViewDataChanged() " + userId);
12133ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen        }
12143ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1215976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1216976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
12173ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1218976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (appWidgetIds == null || appWidgetIds.length == 0) {
1219976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1220119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
1221742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1222976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1223976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1224742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1225976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = appWidgetIds.length;
1226742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
1227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int appWidgetId = appWidgetIds[i];
1228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1229976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // NOTE: The lookup is enforcing security across users by making
1230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // sure the caller can only access widgets it hosts or provides.
1231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = lookupWidgetLocked(appWidgetId,
1232976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Binder.getCallingUid(), callingPackage);
1233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget != null) {
1235976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    scheduleNotifyAppWidgetViewDataChanged(widget, viewId);
1236976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1237742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1238742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1239742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1240742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1241976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1242976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void updateAppWidgetProvider(ComponentName componentName, RemoteViews views) {
1243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1245976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1246976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "updateAppWidgetProvider() " + userId);
1247976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1248976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1249976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1250976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
1251976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1252976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1253976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1254976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1255976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1256976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can access only its providers.
1257976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
1258976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = lookupProviderLocked(providerId);
1259976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1260976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider == null) {
1261976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Provider doesn't exist " + providerId);
1262119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn                return;
1263119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
1264976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1265976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<Widget> instances = provider.widgets;
1266976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = instances.size();
1267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
1268976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = instances.get(i);
1269976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                updateAppWidgetInstanceLocked(widget, views, false);
1270742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1271742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1272742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1273742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1274976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
12758e1d299da27da534b508b1da51ebe351a689cefaSvetoslav    public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,
12768e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            int profileId) {
1277976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1278976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1279976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getInstalledProvidersForProfiles() " + userId);
1281742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
12838e1d299da27da534b508b1da51ebe351a689cefaSvetoslav        // Ensure the profile is in the group and enabled.
12848e1d299da27da534b508b1da51ebe351a689cefaSvetoslav        if (!mSecurityPolicy.isEnabledGroupProfile(profileId)) {
1285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
1286742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1287742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1288976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1289976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1290adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
12918e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            ArrayList<AppWidgetProviderInfo> result = null;
1292742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerCount = mProviders.size();
1294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < providerCount; i++) {
1295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
1296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                AppWidgetProviderInfo info = provider.info;
1297976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1298976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Ignore an invalid provider or one not matching the filter.
1299976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.zombie || (info.widgetCategory & categoryFilter) == 0) {
1300976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
1301976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1302976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
13038e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                // Add providers only for the requested profile that are white-listed.
1304976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int providerProfileId = info.getProfile().getIdentifier();
13058e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                if (providerProfileId == profileId
13068e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                        && mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed(
13078e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                            provider.id.componentName.getPackageName(), providerProfileId)) {
13088e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                    if (result == null) {
13098e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                        result = new ArrayList<>();
1310976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
13118e1d299da27da534b508b1da51ebe351a689cefaSvetoslav                    result.add(cloneIfLocalBinder(info));
1312976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1313742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1314976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1315976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return result;
1316742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1317742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1318742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1319976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void updateAppWidgetIds(String callingPackage, int[] appWidgetIds,
1320976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            RemoteViews views, boolean partially) {
1321976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1322976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1323976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (appWidgetIds == null || appWidgetIds.length == 0) {
1324976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1325742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1326742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1327976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1328976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1329976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1330976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int bitmapMemoryUsage = (views != null) ? views.estimateMemoryUsage() : 0;
1331976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) {
1332976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            throw new IllegalArgumentException("RemoteViews for widget update exceeds"
1333976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + " maximum bitmap memory usage (used: " + bitmapMemoryUsage
1334976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + ", max: " + mMaxWidgetBitmapMemory + ")");
1335742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1336742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1337976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1338976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1339742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1340976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = appWidgetIds.length;
1341483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            for (int i = 0; i < N; i++) {
1342976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int appWidgetId = appWidgetIds[i];
1343976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1344976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // NOTE: The lookup is enforcing security across users by making
1345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // sure the caller can only access widgets it hosts or provides.
1346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = lookupWidgetLocked(appWidgetId,
1347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Binder.getCallingUid(), callingPackage);
1348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget != null) {
1350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    updateAppWidgetInstanceLocked(widget, views, partially);
1351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1352483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            }
1353742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1354742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1355742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int incrementAndGetAppWidgetIdLocked(int userId) {
1357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int appWidgetId = peekNextAppWidgetIdLocked(userId) + 1;
1358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mNextAppWidgetIds.put(userId, appWidgetId);
1359976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return appWidgetId;
1360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1362976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void setMinAppWidgetIdLocked(int userId, int minWidgetId) {
1363976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int nextAppWidgetId = peekNextAppWidgetIdLocked(userId);
1364976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (nextAppWidgetId < minWidgetId) {
1365976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mNextAppWidgetIds.put(userId, minWidgetId);
1366742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1367976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1368976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int peekNextAppWidgetIdLocked(int userId) {
1370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (mNextAppWidgetIds.indexOfKey(userId) < 0) {
1371976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return AppWidgetManager.INVALID_APPWIDGET_ID + 1;
1372742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } else {
1373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return mNextAppWidgetIds.get(userId);
1374742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1375742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1376742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1377976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Host lookupOrAddHostLocked(HostId id) {
1378976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Host host = lookupHostLocked(id);
1379976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (host != null) {
1380976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return host;
1381976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1382976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1383976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host = new Host();
1384976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host.id = id;
1385976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mHosts.add(host);
1386976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1387976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return host;
1388742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1389742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1390976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void deleteHostLocked(Host host) {
1391976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = host.widgets.size();
1392976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = N - 1; i >= 0; i--) {
1393976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = host.widgets.remove(i);
1394976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            deleteAppWidgetLocked(widget);
1395976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1396976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mHosts.remove(host);
1397976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1398976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // it's gone or going away, abruptly drop the callback connection
1399976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host.callbacks = null;
1400742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1401742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1402976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void deleteAppWidgetLocked(Widget widget) {
1403976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We first unbind all services that are bound to this id
1404976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        unbindAppWidgetRemoteViewsServicesLocked(widget);
1405976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1406976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Host host = widget.host;
1407976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host.widgets.remove(widget);
1408976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pruneHostLocked(host);
1409976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1410976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mWidgets.remove(widget);
1411976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1412976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider = widget.provider;
1413976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider != null) {
1414976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.widgets.remove(widget);
1415976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!provider.zombie) {
1416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // send the broacast saying that this appWidgetId has been deleted
1417976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendDeletedIntentLocked(widget);
1418976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1419976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.widgets.isEmpty()) {
1420976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // cancel the future updates
1421976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    cancelBroadcasts(provider);
1422976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // send the broacast saying that the provider is not in use any more
1424976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    sendDisabledIntentLocked(provider);
1425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1426976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1427742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1428742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1429742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1430976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void cancelBroadcasts(Provider provider) {
1431976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "cancelBroadcasts() for " + provider);
1433976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1434976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider.broadcast != null) {
1435976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mAlarmManager.cancel(provider.broadcast);
1436742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            long token = Binder.clearCallingIdentity();
1437742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            try {
1438976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                provider.broadcast.cancel();
1439742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } finally {
1440742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Binder.restoreCallingIdentity(token);
1441742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1442976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.broadcast = null;
1443742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1444742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1445742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1446976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Unbinds from a RemoteViewsService when we delete an app widget
1447976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void unbindAppWidgetRemoteViewsServicesLocked(Widget widget) {
1448976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int appWidgetId = widget.appWidgetId;
1449976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Unbind all connections to Services bound to this AppWidgetId
1450976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet()
1451976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                .iterator();
1452976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        while (it.hasNext()) {
1453976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final Pair<Integer, Intent.FilterComparison> key = it.next();
1454976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (key.first == appWidgetId) {
1455976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final ServiceConnectionProxy conn = (ServiceConnectionProxy)
1456976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mBoundRemoteViewsServices.get(key);
1457976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                conn.disconnect();
1458976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.unbindService(conn);
1459976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                it.remove();
1460976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1461742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1462976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1463976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Check if we need to destroy any services (if no other app widgets are
1464976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // referencing the same service)
1465976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        decrementAppWidgetServiceRefCount(widget);
1466742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1467742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1468976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
1469976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void destroyRemoteViewsService(final Intent intent, Widget widget) {
1470976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final ServiceConnection conn = new ServiceConnection() {
1471976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            @Override
1472976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public void onServiceConnected(ComponentName name, IBinder service) {
1473976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service);
1474976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                try {
1475976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    cb.onDestroy(intent);
1476976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } catch (RemoteException re) {
1477976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.e(TAG, "Error calling remove view factory", re);
1478976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1479976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.unbindService(this);
1480742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1481976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1482976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            @Override
1483976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public void onServiceDisconnected(ComponentName name) {
1484976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Do nothing
1485976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1486976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        };
1487976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1488976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Bind to the service and remove the static intent->factory mapping in the
1489976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // RemoteViewsService.
1490976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long token = Binder.clearCallingIdentity();
1491976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1492976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE,
1493976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    widget.provider.info.getProfile());
1494976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
1495976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(token);
1496742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1497742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1498742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Adds to the ref-count for a given RemoteViewsService intent
1500976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void incrementAppWidgetServiceRefCount(int appWidgetId,
1501976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> serviceId) {
1502976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        HashSet<Integer> appWidgetIds = null;
1503976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (mRemoteViewsServicesAppWidgets.containsKey(serviceId)) {
1504976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            appWidgetIds = mRemoteViewsServicesAppWidgets.get(serviceId);
1505976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } else {
1506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            appWidgetIds = new HashSet<>();
1507976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mRemoteViewsServicesAppWidgets.put(serviceId, appWidgetIds);
150875b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka        }
1509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        appWidgetIds.add(appWidgetId);
151075b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka    }
151175b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka
1512976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
1513976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // the ref-count reaches zero.
1514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void decrementAppWidgetServiceRefCount(Widget widget) {
1515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Iterator<Pair<Integer, FilterComparison>> it = mRemoteViewsServicesAppWidgets
1516976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                .keySet().iterator();
1517976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        while (it.hasNext()) {
1518976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final Pair<Integer, FilterComparison> key = it.next();
1519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
1520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (ids.remove(widget.appWidgetId)) {
1521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If we have removed the last app widget referencing this service, then we
1522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // should destroy it and remove it from this set
1523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (ids.isEmpty()) {
1524976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    destroyRemoteViewsService(key.second.getIntent(), widget);
1525976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    it.remove();
1526976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
152775b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka            }
152875b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka        }
152975b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka    }
153075b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka
1531976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void saveGroupStateAsync(int groupId) {
1532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSaveStateHandler.post(new SaveStateRunnable(groupId));
1533976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1534976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1535976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void updateAppWidgetInstanceLocked(Widget widget, RemoteViews views,
1536976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean isPartialUpdate) {
1537976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget != null && widget.provider != null
1538976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                && !widget.provider.zombie && !widget.host.zombie) {
1539976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isPartialUpdate && widget.views != null) {
1541976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // For a partial update, we merge the new RemoteViews with the old.
1542976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                widget.views.mergeRemoteViews(views);
1543976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
1544976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // For a full update we replace the RemoteViews completely.
1545976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                widget.views = views;
1546adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1547976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
15483de01b2e3474ac2eaccbcf72b6693bb19d254824Svet Ganov            scheduleNotifyUpdateAppWidgetLocked(widget, views);
1549adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1550adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1551adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1552976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) {
1553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget == null || widget.host == null || widget.host.zombie
1554976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.host.callbacks == null || widget.provider == null
1555976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.provider.zombie) {
1556976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1557976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1558976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1559976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        SomeArgs args = SomeArgs.obtain();
1560976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg1 = widget.host;
1561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg2 = widget.host.callbacks;
1562976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi1 = widget.appWidgetId;
1563976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi2 = viewId;
1564976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1565976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler.obtainMessage(
1566976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                CallbackHandler.MSG_NOTIFY_VIEW_DATA_CHANGED,
1567976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                args).sendToTarget();
1568adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1569adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1570976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1571976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
1572976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int appWidgetId, int viewId) {
1573976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1574976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.viewDataChanged(appWidgetId, viewId);
1575976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1576976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // It failed; remove the callback. No need to prune because
1577976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we know that this host is still referenced by this instance.
1578976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks = null;
1579976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1580976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1581976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // If the host is unavailable, then we call the associated
1582976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // RemoteViewsFactory.onDataSetChanged() directly
1583976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1584976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (callbacks == null) {
1585976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1586976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1587976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Set<Pair<Integer, FilterComparison>> keys = mRemoteViewsServicesAppWidgets.keySet();
1588976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (Pair<Integer, FilterComparison> key : keys) {
1589976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (mRemoteViewsServicesAppWidgets.get(key).contains(appWidgetId)) {
1590976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final ServiceConnection connection = new ServiceConnection() {
1591976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            @Override
1592976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            public void onServiceConnected(ComponentName name, IBinder service) {
1593976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                IRemoteViewsFactory cb = IRemoteViewsFactory.Stub
1594976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        .asInterface(service);
1595976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                try {
1596976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    cb.onDataSetChangedAsync();
1597976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                } catch (RemoteException e) {
1598976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.e(TAG, "Error calling onDataSetChangedAsync()", e);
1599976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
1600976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                mContext.unbindService(this);
1601976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
1602976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            @Override
1604976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            public void onServiceDisconnected(android.content.ComponentName name) {
1605976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // Do nothing
1606976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
1607976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        };
1608976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1609976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int userId = UserHandle.getUserId(key.first);
1610976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Intent intent = key.second.getIntent();
1611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1612976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // Bind to the service and call onDataSetChanged()
1613976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        bindService(intent, connection, new UserHandle(userId));
1614976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
1615976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1616976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1617976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1618adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1619adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
16203de01b2e3474ac2eaccbcf72b6693bb19d254824Svet Ganov    private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
1621976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget == null || widget.provider == null || widget.provider.zombie
1622976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.host.callbacks == null || widget.host.zombie) {
1623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1624976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1625976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1626976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        SomeArgs args = SomeArgs.obtain();
1627976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg1 = widget.host;
1628976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg2 = widget.host.callbacks;
16293de01b2e3474ac2eaccbcf72b6693bb19d254824Svet Ganov        args.arg3 = updateViews;
1630976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi1 = widget.appWidgetId;
1631976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1632976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler.obtainMessage(
1633976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET,
1634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                args).sendToTarget();
1635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1636976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1637976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
1638976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int appWidgetId, RemoteViews views) {
1639976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1640976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.updateAppWidget(appWidgetId, views);
1641976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1642976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
1643976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget host dead: " + host.id, re);
1644976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1645976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1646adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1647adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1648adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1649976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void scheduleNotifyProviderChangedLocked(Widget widget) {
1650976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget == null || widget.provider == null || widget.provider.zombie
1651976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.host.callbacks == null || widget.host.zombie) {
1652976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1654976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1655976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        SomeArgs args = SomeArgs.obtain();
1656976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg1 = widget.host;
1657976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg2 = widget.host.callbacks;
1658976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg3 = widget.provider.info;
1659976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi1 = widget.appWidgetId;
1660976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1661976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler.obtainMessage(
1662976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                CallbackHandler.MSG_NOTIFY_PROVIDER_CHANGED,
1663976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                args).sendToTarget();
1664976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1665976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1666976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
1667976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int appWidgetId, AppWidgetProviderInfo info) {
1668976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1669976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.providerChanged(appWidgetId, info);
1670976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1671976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock){
1672976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget host dead: " + host.id, re);
1673976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1674976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1675976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1676976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1677976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
16786bd702538d90005add1cfc33746da19404090dc1Svet Ganov    private void scheduleNotifyGroupHostsForProvidersChangedLocked(int userId) {
16796bd702538d90005add1cfc33746da19404090dc1Svet Ganov        final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
16806bd702538d90005add1cfc33746da19404090dc1Svet Ganov
1681976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mHosts.size();
1682976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = N - 1; i >= 0; i--) {
1683976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
1684976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
16856bd702538d90005add1cfc33746da19404090dc1Svet Ganov            boolean hostInGroup = false;
16866bd702538d90005add1cfc33746da19404090dc1Svet Ganov            final int M = profileIds.length;
16876bd702538d90005add1cfc33746da19404090dc1Svet Ganov            for (int j = 0; j < M; j++) {
16886bd702538d90005add1cfc33746da19404090dc1Svet Ganov                final int profileId = profileIds[j];
16896bd702538d90005add1cfc33746da19404090dc1Svet Ganov                if (host.getUserId() == profileId) {
16906bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    hostInGroup = true;
16916bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    break;
16926bd702538d90005add1cfc33746da19404090dc1Svet Ganov                }
16936bd702538d90005add1cfc33746da19404090dc1Svet Ganov            }
16946bd702538d90005add1cfc33746da19404090dc1Svet Ganov
16956bd702538d90005add1cfc33746da19404090dc1Svet Ganov            if (!hostInGroup) {
16966bd702538d90005add1cfc33746da19404090dc1Svet Ganov                continue;
16976bd702538d90005add1cfc33746da19404090dc1Svet Ganov            }
16986bd702538d90005add1cfc33746da19404090dc1Svet Ganov
1699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host == null || host.zombie || host.callbacks == null) {
1700976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                continue;
1701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1702976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1703976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            SomeArgs args = SomeArgs.obtain();
1704976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            args.arg1 = host;
1705976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            args.arg2 = host.callbacks;
1706976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1707976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mCallbackHandler.obtainMessage(
1708976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    CallbackHandler.MSG_NOTIFY_PROVIDERS_CHANGED,
1709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args).sendToTarget();
1710adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1711976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks) {
1714976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1715976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.providersChanged();
1716976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1717976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
1718976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget host dead: " + host.id, re);
1719976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1720976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1721adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1722976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static boolean isLocalBinder() {
1725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return Process.myPid() == Binder.getCallingPid();
1726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static RemoteViews cloneIfLocalBinder(RemoteViews rv) {
1729976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (isLocalBinder() && rv != null) {
1730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return rv.clone();
1731adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1732976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return rv;
1733976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1734976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1735976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
1736976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (isLocalBinder() && info != null) {
1737976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return info.clone();
1738adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1739976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return info;
1740976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1741976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1742976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static Bundle cloneIfLocalBinder(Bundle bundle) {
1743976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Note: this is only a shallow copy. For now this will be fine, but it could be problematic
1744976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // if we start adding objects to the options. Further, it would only be an issue if keyguard
1745976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // used such options.
1746976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (isLocalBinder() && bundle != null) {
1747976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return (Bundle) bundle.clone();
1748adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1749976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return bundle;
1750adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1751adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1752976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Widget lookupWidgetLocked(int appWidgetId, int uid, String packageName) {
1753976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mWidgets.size();
1754adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        for (int i = 0; i < N; i++) {
1755976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = mWidgets.get(i);
1756976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.appWidgetId == appWidgetId
1757976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && mSecurityPolicy.canAccessAppWidget(widget, uid, packageName)) {
1758976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return widget;
1759adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1760976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1761976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
1762976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1763976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1764976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Provider lookupProviderLocked(ProviderId id) {
1765976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mProviders.size();
1766976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < N; i++) {
1767976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
1768976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider.id.equals(id)) {
1769976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return provider;
1770adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1771adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1772976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
1773adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1774adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1775976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Host lookupHostLocked(HostId hostId) {
1776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mHosts.size();
1777976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < N; i++) {
1778976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
1779976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host.id.equals(hostId)) {
1780976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return host;
1781976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1782adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1783976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
1784976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1785adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void pruneHostLocked(Host host) {
1787976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (host.widgets.size() == 0 && host.callbacks == null) {
1788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
1789976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Pruning host " + host.id);
1790adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1791976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mHosts.remove(host);
1792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1793976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1794adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1795976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void loadGroupWidgetProvidersLocked(int[] profileIds) {
1796976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<ResolveInfo> allReceivers = null;
1797976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1798adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1799976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileCount = profileIds.length;
1800976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileCount; i++) {
1801976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
1802adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1803976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            List<ResolveInfo> receivers = queryIntentReceivers(intent, profileId);
1804976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (receivers != null && !receivers.isEmpty()) {
1805976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (allReceivers == null) {
1806976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    allReceivers = new ArrayList<>();
1807adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
1808976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                allReceivers.addAll(receivers);
1809adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1810976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1811adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1812976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = (allReceivers == null) ? 0 : allReceivers.size();
1813976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < N; i++) {
1814976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ResolveInfo receiver = allReceivers.get(i);
1815976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            addProviderLocked(receiver);
1816adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1817adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1818adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1819976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean addProviderLocked(ResolveInfo ri) {
1820976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1821976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
1822adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1823976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1824976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!ri.activityInfo.isEnabled()) {
1825976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
1826adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1827adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1828976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ComponentName componentName = new ComponentName(ri.activityInfo.packageName,
1829976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ri.activityInfo.name);
1830976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName);
1831976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1832976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider = parseProviderInfoXml(providerId, ri);
1833976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider != null) {
1834976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we might have an inactive entry for this provider already due to
1835976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // a preceding restore operation.  if so, fix it up in place; otherwise
1836976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // just add this new one.
1837976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider existing = lookupProviderLocked(providerId);
1838976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1839976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If the provider was not found it may be because it was restored and
1840976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we did not know its UID so let us find if there is such one.
1841976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (existing == null) {
1842ad870c3d9c58a9ee31cdf4a9807a4cec2e68ab04Svetoslav                ProviderId restoredProviderId = new ProviderId(UNKNOWN_UID, componentName);
1843ad870c3d9c58a9ee31cdf4a9807a4cec2e68ab04Svetoslav                existing = lookupProviderLocked(restoredProviderId);
1844adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1845adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1846976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (existing != null) {
1847976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (existing.zombie && !mSafeMode) {
1848976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // it's a placeholder that was set up during an app restore
1849ad870c3d9c58a9ee31cdf4a9807a4cec2e68ab04Svetoslav                    existing.id = providerId;
1850976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    existing.zombie = false;
1851976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    existing.info = provider.info; // the real one filled out from the ResolveInfo
1852976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
1853976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "Provider placeholder now reified: " + existing);
1854976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
1855adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
1856976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
1857976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mProviders.add(provider);
1858adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1859976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
1860adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1861adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return false;
1863976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1864adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1865976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void deleteProviderLocked(Provider provider) {
1866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int N = provider.widgets.size();
1867298a6c6b29798647b3d8f12d0723b1e49fc8b8daSvetoslav        for (int i = N - 1; i >= 0; i--) {
1868976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = provider.widgets.remove(i);
1869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Call back with empty RemoteViews
1870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            updateAppWidgetInstanceLocked(widget, null, false);
1871976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // clear out references to this appWidgetId
1872976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host.widgets.remove(widget);
1873976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.remove(widget);
1874976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider = null;
1875976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pruneHostLocked(widget.host);
1876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host = null;
1877adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mProviders.remove(provider);
1879976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1880976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // no need to send the DISABLE broadcast, since the receiver is gone anyway
1881976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        cancelBroadcasts(provider);
1882adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1883adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1884976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendEnableIntentLocked(Provider p) {
1885976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
1886976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(p.info.provider);
1887976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, p.info.getProfile());
1888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1889adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1890976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) {
1891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
1893976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(provider.info.provider);
1894976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, provider.info.getProfile());
1895adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1896adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1897976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendDeletedIntentLocked(Widget widget) {
1898976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
1899976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(widget.provider.info.provider);
1900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
1901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, widget.provider.info.getProfile());
1902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendDisabledIntentLocked(Provider provider) {
1905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
1906976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(provider.info.provider);
1907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, provider.info.getProfile());
1908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1909976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void sendOptionsChangedIntentLocked(Widget widget) {
1911976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED);
1912976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(widget.provider.info.provider);
1913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
1914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options);
1915976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, widget.provider.info.getProfile());
1916976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1918976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) {
1919976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider.info.updatePeriodMillis > 0) {
1920976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // if this is the first instance, set the alarm. otherwise,
1921976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // rely on the fact that we've already set it and that
1922976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // PendingIntent.getBroadcast will update the extras.
1923976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean alreadyRegistered = provider.broadcast != null;
1924976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1925976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
1926976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.setComponent(provider.info.provider);
1927976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            long token = Binder.clearCallingIdentity();
1928976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
1929976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
1930976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        PendingIntent.FLAG_UPDATE_CURRENT, provider.info.getProfile());
1931976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
1932976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(token);
1933976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1934976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!alreadyRegistered) {
1935976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                long period = provider.info.updatePeriodMillis;
1936976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (period < MIN_UPDATE_PERIOD) {
1937976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    period = MIN_UPDATE_PERIOD;
1938adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
1939976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1940976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        SystemClock.elapsedRealtime() + period, period, provider.broadcast);
1941adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1942adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1943adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1944adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static int[] getWidgetIds(ArrayList<Widget> widgets) {
1946976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int instancesSize = widgets.size();
1947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int appWidgetIds[] = new int[instancesSize];
1948976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < instancesSize; i++) {
1949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            appWidgetIds[i] = widgets.get(i).appWidgetId;
1950adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return appWidgetIds;
1952adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1953adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpProvider(Provider provider, int index, PrintWriter pw) {
1955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        AppWidgetProviderInfo info = provider.info;
1956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print("] provider ");
1957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(provider.id);
1958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    min=("); pw.print(info.minWidth);
1959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("x"); pw.print(info.minHeight);
1960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(")   minResize=("); pw.print(info.minResizeWidth);
1961976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("x"); pw.print(info.minResizeHeight);
1962976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(") updatePeriodMillis=");
1963976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.updatePeriodMillis);
1964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" resizeMode=");
1965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.resizeMode);
1966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.widgetCategory);
1967976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" autoAdvanceViewId=");
1968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.autoAdvanceViewId);
1969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" initialLayout=#");
1970976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(Integer.toHexString(info.initialLayout));
1971976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" initialKeyguardLayout=#");
1972976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(Integer.toHexString(info.initialKeyguardLayout));
1973976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" zombie="); pw.println(provider.zombie);
1974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpHost(Host host, int index, PrintWriter pw) {
1977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print("] hostId=");
1978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(host.id);
1979976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    callbacks="); pw.println(host.callbacks);
1980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    widgets.size="); pw.print(host.widgets.size());
1981976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" zombie="); pw.println(host.zombie);
1982976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw) {
1985976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print(']');
1986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" user="); pw.print(grant.first);
1987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" package="); pw.println(grant.second);
1988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpWidget(Widget widget, int index, PrintWriter pw) {
1991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print("] id=");
1992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(widget.appWidgetId);
1993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    host=");
1994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(widget.host.id);
1995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.provider != null) {
1996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.print("    provider="); pw.println(widget.provider.id);
1997adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1998976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.host != null) {
1999976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.print("    host.callbacks="); pw.println(widget.host.callbacks);
2000976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2001976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.views != null) {
2002976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.print("    views="); pw.println(widget.views);
2003976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2004976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2005976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void serializeProvider(XmlSerializer out, Provider p) throws IOException {
2007976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.startTag(null, "p");
2008976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "pkg", p.info.provider.getPackageName());
2009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "cl", p.info.provider.getClassName());
2010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "tag", Integer.toHexString(p.tag));
2011976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.endTag(null, "p");
2012976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void serializeHost(XmlSerializer out, Host host) throws IOException {
2015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.startTag(null, "h");
2016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "pkg", host.id.packageName);
2017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "id", Integer.toHexString(host.id.hostId));
2018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "tag", Integer.toHexString(host.tag));
2019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.endTag(null, "h");
2020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2021adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void serializeAppWidget(XmlSerializer out, Widget widget) throws IOException {
2023976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.startTag(null, "g");
2024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "id", Integer.toHexString(widget.appWidgetId));
2025976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "rid", Integer.toHexString(widget.restoredId));
2026976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "h", Integer.toHexString(widget.host.tag));
2027976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.provider != null) {
2028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "p", Integer.toHexString(widget.provider.tag));
2029976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.options != null) {
2031976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "min_width", Integer.toHexString(widget.options.getInt(
2032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)));
2033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "min_height", Integer.toHexString(widget.options.getInt(
2034976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)));
2035976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "max_width", Integer.toHexString(widget.options.getInt(
2036976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)));
2037976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "max_height", Integer.toHexString(widget.options.getInt(
2038976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)));
2039976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt(
2040976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)));
2041adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
2042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.endTag(null, "g");
2043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2044adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2045976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public List<String> getWidgetParticipants(int userId) {
2047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return mBackupRestoreController.getWidgetParticipants(userId);
2048976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2049adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2050976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public byte[] getWidgetState(String packageName, int userId) {
2052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return mBackupRestoreController.getWidgetState(packageName, userId);
2053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2054adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void restoreStarting(int userId) {
2057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController.restoreStarting(userId);
2058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2059adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2060976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2061976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void restoreWidgetState(String packageName, byte[] restoredState, int userId) {
2062976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController.restoreWidgetState(packageName, restoredState, userId);
2063976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2064adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2065976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2066976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void restoreFinished(int userId) {
2067976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController.restoreFinished(userId);
2068976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2069adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2070976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @SuppressWarnings("deprecation")
2071976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri) {
2072976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider = null;
2073742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2074742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        ActivityInfo activityInfo = ri.activityInfo;
2075742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        XmlResourceParser parser = null;
2076742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2077483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(),
2078742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
2079742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (parser == null) {
2080742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER
2081976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " meta-data for " + "AppWidget provider '" + providerId + '\'');
2082742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return null;
2083742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2084742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2085742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            AttributeSet attrs = Xml.asAttributeSet(parser);
2086742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2087742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            int type;
2088742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2089742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    && type != XmlPullParser.START_TAG) {
2090742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                // drain whitespace, comments, etc.
2091742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2092742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2093742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            String nodeName = parser.getName();
2094742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (!"appwidget-provider".equals(nodeName)) {
2095742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
2096976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " AppWidget provider " + providerId.componentName
2097976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for user " + providerId.uid);
2098742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return null;
2099742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2100742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2101976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider = new Provider();
2102976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.id = providerId;
2103976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            AppWidgetProviderInfo info = provider.info = new AppWidgetProviderInfo();
2104976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            info.provider = providerId.componentName;
2105976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            info.providerInfo = activityInfo;
2106742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2107976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final Resources resources;
2108976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
2109976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
2110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                resources = mContext.getPackageManager()
2111976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        .getResourcesForApplicationAsUser(activityInfo.packageName,
2112976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                UserHandle.getUserId(providerId.uid));
2113976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
2114976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
2115976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2116742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2117976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            TypedArray sa = resources.obtainAttributes(attrs,
2118742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo);
2119742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2120742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // These dimensions has to be resolved in the application's context.
2121742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // We simply send back the raw complex data, which will be
2122742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
2123742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            TypedValue value = sa
2124742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
2125742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minWidth = value != null ? value.data : 0;
2126742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
2127742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minHeight = value != null ? value.data : 0;
2128742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            value = sa.peekValue(
2129742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
2130742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minResizeWidth = value != null ? value.data : info.minWidth;
2131742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            value = sa.peekValue(
2132742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
2133742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minResizeHeight = value != null ? value.data : info.minHeight;
2134742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.updatePeriodMillis = sa.getInt(
2135742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
2136742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.initialLayout = sa.getResourceId(
2137742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
21380aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen            info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
21390aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                    AppWidgetProviderInfo_initialKeyguardLayout, 0);
2140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2141742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            String className = sa
2142742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
2143742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (className != null) {
2144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                info.configure = new ComponentName(providerId.componentName.getPackageName(),
2145976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        className);
2146742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2147483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString();
2148742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.icon = ri.getIconResource();
2149742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.previewImage = sa.getResourceId(
2150742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
2151742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.autoAdvanceViewId = sa.getResourceId(
2152742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
2153742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.resizeMode = sa.getInt(
2154742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
2155742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    AppWidgetProviderInfo.RESIZE_NONE);
21560aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen            info.widgetCategory = sa.getInt(
2157ca5e341574774379f157a4ea579a1732bd4cf7fbMichael Jurka                    com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory,
21580aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                    AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
2159742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2160742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            sa.recycle();
2161976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
2162742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // Ok to catch Exception here, because anything going wrong because
2163742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // of what a client process passes to us should not be fatal for the
2164742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // system process.
2165976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.w(TAG, "XML parsing failed for AppWidget provider "
2166976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + providerId.componentName + " for user " + providerId.uid, e);
2167742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return null;
2168742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } finally {
2169976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (parser != null) {
2170742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                parser.close();
2171976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2172742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2173976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return provider;
2174742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2175742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2176976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int getUidForPackage(String packageName, int userId) {
2177483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        PackageInfo pkgInfo = null;
2178976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2179976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2180483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        try {
2181976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pkgInfo = mPackageManager.getPackageInfo(packageName, 0, userId);
2182483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        } catch (RemoteException re) {
2183483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            // Shouldn't happen, local call
2184976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2185976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2186483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        }
2187976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2188742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        if (pkgInfo == null || pkgInfo.applicationInfo == null) {
2189976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return -1;
2190742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2191976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2192742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        return pkgInfo.applicationInfo.uid;
2193742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2194742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2195976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private ActivityInfo getProviderInfo(ComponentName componentName, int userId) {
2196976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2197976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(componentName);
2198976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2199976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<ResolveInfo> receivers = queryIntentReceivers(intent, userId);
2200976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We are setting component, so there is only one or none.
2201976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!receivers.isEmpty()) {
2202976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return receivers.get(0).activityInfo;
2203f229e4d3eb8f910c181f96416c6798f6f305a395Jim Miller        }
2204976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2205976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2206f229e4d3eb8f910c181f96416c6798f6f305a395Jim Miller    }
2207f229e4d3eb8f910c181f96416c6798f6f305a395Jim Miller
2208976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private List<ResolveInfo> queryIntentReceivers(Intent intent, int userId) {
2209976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2210742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2211d00bb5edcfc8ee5c2026f66785b703b388314b22Adam Lesinski            int flags = PackageManager.GET_META_DATA;
2212d00bb5edcfc8ee5c2026f66785b703b388314b22Adam Lesinski
2213d00bb5edcfc8ee5c2026f66785b703b388314b22Adam Lesinski            // Widgets referencing shared libraries need to have their
2214d00bb5edcfc8ee5c2026f66785b703b388314b22Adam Lesinski            // dependencies loaded.
2215d00bb5edcfc8ee5c2026f66785b703b388314b22Adam Lesinski            flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
2216d00bb5edcfc8ee5c2026f66785b703b388314b22Adam Lesinski
2217976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return mPackageManager.queryIntentReceivers(intent,
2218976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2219d00bb5edcfc8ee5c2026f66785b703b388314b22Adam Lesinski                    flags, userId);
2220976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
2221976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return Collections.emptyList();
2222976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2223976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2224742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2225742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2226742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onUserStarted(int userId) {
2228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
2229976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
2230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mProviders.size();
2232742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
2234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2235976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Send broadcast only to the providers of the user.
2236976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() != userId) {
2237976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2238976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2239976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2240976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.widgets.size() > 0) {
2241976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    sendEnableIntentLocked(provider);
2242976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int[] appWidgetIds = getWidgetIds(provider.widgets);
2243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    sendUpdateIntentLocked(provider, appWidgetIds);
2244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    registerForBroadcastsLocked(provider, appWidgetIds);
2245742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2246742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2247742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2248742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2249742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2250742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    // only call from initialization -- it assumes that the data structures are all empty
2251976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void loadGroupStateLocked(int[] profileIds) {
2252976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We can bind the widgets to host and providers only after
2253976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // reading the host and providers for all users since a widget
2254976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // can have a host and a provider in different users.
2255976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<LoadedWidgetState> loadedWidgets = new ArrayList<>();
2256742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2257976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int version = 0;
2258976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2259976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileIdCount = profileIds.length;
2260976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileIdCount; i++) {
2261976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
2262976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2263976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // No file written for this user - nothing to do.
2264976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            AtomicFile file = getSavedStateFile(profileId);
2265976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
2266976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                FileInputStream stream = file.openRead();
2267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                version = readProfileStateFromFileLocked(stream, profileId, loadedWidgets);
2268976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                IoUtils.closeQuietly(stream);
2269976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (FileNotFoundException e) {
2270976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Failed to read state: " + e);
2271976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2272976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2273976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2274976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (version >= 0) {
2275976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Hooke'm up...
2276976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            bindLoadedWidgets(loadedWidgets);
2277976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2278976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // upgrade the database if needed
2279976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            performUpgradeLocked(version);
2280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } else {
2281976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // failed reading, clean up
2282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
2283976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.clear();
2284976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mHosts.clear();
2285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mProviders.size();
2286976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
2287976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mProviders.get(i).widgets.clear();
2288742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2289742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2290742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2291742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2292976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void bindLoadedWidgets(List<LoadedWidgetState> loadedWidgets) {
2293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int loadedWidgetCount = loadedWidgets.size();
2294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = loadedWidgetCount - 1; i >= 0; i--) {
2295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            LoadedWidgetState loadedWidget = loadedWidgets.remove(i);
2296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = loadedWidget.widget;
2297976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2298976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider = findProviderByTag(loadedWidget.providerTag);
2299976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.provider == null) {
2300976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // This provider is gone. We just let the host figure out
2301976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // that this happened when it fails to load it.
2302976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                continue;
2303976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2304976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2305976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host = findHostByTag(loadedWidget.hostTag);
2306976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.host == null) {
2307976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // This host is gone.
2308976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                continue;
2309976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2310976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2311976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider.widgets.add(widget);
2312976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host.widgets.add(widget);
2313976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.add(widget);
2314119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
2315976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2316976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2317976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Provider findProviderByTag(int tag) {
2318976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (tag < 0) {
2319976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
2320976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2321976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int providerCount = mProviders.size();
2322976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < providerCount; i++) {
2323976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2324976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider.tag == tag) {
2325976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return provider;
2326976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2327976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2328976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2329976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2330976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2331976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Host findHostByTag(int tag) {
2332976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (tag < 0) {
2333976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
2334976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2335976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostCount = mHosts.size();
2336976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < hostCount; i++) {
2337976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
2338976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host.tag == tag) {
2339976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return host;
2340742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2341976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2342976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2343976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2344976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void saveStateLocked(int userId) {
2346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        tagProvidersAndHosts();
2347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
2349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileCount = profileIds.length;
2351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileCount; i++) {
2352976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
2353976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2354976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            AtomicFile file = getSavedStateFile(profileId);
2355976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            FileOutputStream stream;
2356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
2357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                stream = file.startWrite();
2358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (writeProfileStateToFileLocked(stream, profileId)) {
2359976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    file.finishWrite(stream);
2360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } else {
2361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    file.failWrite(stream);
2362976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.w(TAG, "Failed to save state, restoring backup.");
2363976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2364976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (IOException e) {
2365976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Failed open state file for write: " + e);
2366976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2367976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2368976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void tagProvidersAndHosts() {
2371976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int providerCount = mProviders.size();
2372976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < providerCount; i++) {
2373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2374976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.tag = i;
2375976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2376976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2377976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostCount = mHosts.size();
2378976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < hostCount; i++) {
2379976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
2380976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            host.tag = i;
2381742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2382742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2383742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2384c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav    private void clearProvidersAndHostsTagsLocked() {
2385c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav        final int providerCount = mProviders.size();
2386c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav        for (int i = 0; i < providerCount; i++) {
2387c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav            Provider provider = mProviders.get(i);
2388c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav            provider.tag = TAG_UNDEFINED;
2389c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav        }
2390c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav
2391c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav        final int hostCount = mHosts.size();
2392c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav        for (int i = 0; i < hostCount; i++) {
2393c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav            Host host = mHosts.get(i);
2394c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav            host.tag = TAG_UNDEFINED;
2395c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav        }
2396c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav    }
2397c616b3e2f16c99c51e0543256c219e799ff32232Svetoslav
2398976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean writeProfileStateToFileLocked(FileOutputStream stream, int userId) {
2399742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        int N;
2400742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2401742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2402742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            XmlSerializer out = new FastXmlSerializer();
2403742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.setOutput(stream, "utf-8");
2404742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.startDocument(null, true);
2405742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.startTag(null, "gs");
240639d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            out.attribute(null, "version", String.valueOf(CURRENT_VERSION));
2407976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2408976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mProviders.size();
2409742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2410976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
2411976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only providers for the user.
2412976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() != userId) {
2413976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2414976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2415976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.widgets.size() > 0) {
2416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    serializeProvider(out, provider);
2417742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2418742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2419742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2420742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            N = mHosts.size();
2421742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2422742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Host host = mHosts.get(i);
2423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only hosts for the user.
2424976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (host.getUserId() != userId) {
2425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2426976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2427adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                serializeHost(out, host);
2428742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2429742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2430976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mWidgets.size();
2431742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
2433976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only widgets hosted by the user.
2434976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget.host.getUserId() != userId) {
2435976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2436976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2437976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                serializeAppWidget(out, widget);
2438742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2439742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2440976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Iterator<Pair<Integer, String>> it = mPackagesWithBindWidgetPermission.iterator();
244161a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka            while (it.hasNext()) {
2442976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> binding = it.next();
2443976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only white listings for the user.
2444976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (binding.first != userId) {
2445976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2446976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
244761a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                out.startTag(null, "b");
2448976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                out.attribute(null, "packageName", binding.second);
244961a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                out.endTag(null, "b");
245061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka            }
245161a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
2452742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.endTag(null, "gs");
2453742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.endDocument();
2454742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return true;
2455742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } catch (IOException e) {
2456742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Slog.w(TAG, "Failed to write state: " + e);
2457742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return false;
2458742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2459742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2460742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2461976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int readProfileStateFromFileLocked(FileInputStream stream, int userId,
2462976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            List<LoadedWidgetState> outLoadedWidgets) {
2463976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int version = -1;
2464742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2465742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            XmlPullParser parser = Xml.newPullParser();
2466742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            parser.setInput(stream, null);
2467742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2468976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int legacyProviderIndex = -1;
2469976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int legacyHostIndex = -1;
2470742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            int type;
2471742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            do {
2472742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                type = parser.next();
2473742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                if (type == XmlPullParser.START_TAG) {
2474742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    String tag = parser.getName();
247539d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                    if ("gs".equals(tag)) {
247639d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        String attributeValue = parser.getAttributeValue(null, "version");
247739d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        try {
247839d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                            version = Integer.parseInt(attributeValue);
247939d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        } catch (NumberFormatException e) {
248039d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                            version = 0;
248139d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        }
248239d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                    } else if ("p".equals(tag)) {
2483976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        legacyProviderIndex++;
2484742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // TODO: do we need to check that this package has the same signature
2485742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // as before?
2486742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        String pkg = parser.getAttributeValue(null, "pkg");
2487742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        String cl = parser.getAttributeValue(null, "cl");
2488742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2489976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        pkg = getCanonicalPackageName(pkg, cl, userId);
2490976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (pkg == null) {
2491976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            continue;
2492742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2493742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2494976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(pkg, userId);
2495976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid < 0) {
2496976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            continue;
2497976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
2498976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ComponentName componentName = new ComponentName(pkg, cl);
2500976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2501976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ActivityInfo providerInfo = getProviderInfo(componentName, userId);
2502976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (providerInfo == null) {
2503976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            continue;
2504742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2505976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ProviderId providerId = new ProviderId(uid, componentName);
2507976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Provider provider = lookupProviderLocked(providerId);
2508976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (provider == null && mSafeMode) {
2510976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            // if we're in safe mode, make a temporary one
2511976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider = new Provider();
2512976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.info = new AppWidgetProviderInfo();
2513976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.info.provider = providerId.componentName;
2514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.info.providerInfo = providerInfo;
2515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.zombie = true;
2516976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.id = providerId;
2517976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            mProviders.add(provider);
2518742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        String tagAttribute = parser.getAttributeValue(null, "tag");
2521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int providerTag = !TextUtils.isEmpty(tagAttribute)
2522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex;
2523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        provider.tag = providerTag;
2524742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    } else if ("h".equals(tag)) {
2525976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        legacyHostIndex++;
2526742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        Host host = new Host();
2527742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // TODO: do we need to check that this package has the same signature
2528742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // as before?
2529976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        String pkg = parser.getAttributeValue(null, "pkg");
2530976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2531976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(pkg, userId);
2532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid < 0) {
2533742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            host.zombie = true;
2534742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2535976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2536742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        if (!host.zombie || mSafeMode) {
2537742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // In safe mode, we don't discard the hosts we don't recognize
2538742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // so that they're not pruned from our list. Otherwise, we do.
2539976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int hostId = Integer.parseInt(parser.getAttributeValue(
2540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    null, "id"), 16);
2541976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2542976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            String tagAttribute = parser.getAttributeValue(null, "tag");
2543976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int hostTag = !TextUtils.isEmpty(tagAttribute)
2544976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    ? Integer.parseInt(tagAttribute, 16) : legacyHostIndex;
2545976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2546976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            host.tag = hostTag;
2547976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            host.id = new HostId(uid, hostId, pkg);
2548742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            mHosts.add(host);
2549742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
255061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                    } else if ("b".equals(tag)) {
255161a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                        String packageName = parser.getAttributeValue(null, "packageName");
2552976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(packageName, userId);
2553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid >= 0) {
2554976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            Pair<Integer, String> packageId = Pair.create(userId, packageName);
2555976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            mPackagesWithBindWidgetPermission.add(packageId);
255661a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                        }
2557742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    } else if ("g".equals(tag)) {
2558976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Widget widget = new Widget();
2559976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.appWidgetId = Integer.parseInt(parser.getAttributeValue(
2560976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                null, "id"), 16);
2561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        setMinAppWidgetIdLocked(userId, widget.appWidgetId + 1);
2562742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2563adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                        // restored ID is allowed to be absent
2564adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                        String restoredIdString = parser.getAttributeValue(null, "rid");
2565976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.restoredId = (restoredIdString == null) ? 0
2566adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                                : Integer.parseInt(restoredIdString, 16);
2567adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
25680aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        Bundle options = new Bundle();
25690aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String minWidthString = parser.getAttributeValue(null, "min_width");
25700aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        if (minWidthString != null) {
25710aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
25720aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(minWidthString, 16));
25730aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
25740aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String minHeightString = parser.getAttributeValue(null, "min_height");
2575db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (minHeightString != null) {
25760aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
25770aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(minHeightString, 16));
25780aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
2579db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        String maxWidthString = parser.getAttributeValue(null, "max_width");
2580db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (maxWidthString != null) {
25810aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
25820aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(maxWidthString, 16));
25830aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
25840aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String maxHeightString = parser.getAttributeValue(null, "max_height");
2585db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (maxHeightString != null) {
25860aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
25870aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(maxHeightString, 16));
25880aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
25890aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String categoryString = parser.getAttributeValue(null, "host_category");
2590db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (categoryString != null) {
25910aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
25920aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(categoryString, 16));
25930aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
2594976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.options = options;
25950aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
2596976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int hostTag = Integer.parseInt(parser.getAttributeValue(
2597976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                null, "h"), 16);
2598742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        String providerString = parser.getAttributeValue(null, "p");
2599976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int providerTag = (providerString != null) ? Integer.parseInt(
2600976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                parser.getAttributeValue(null, "p"), 16) : TAG_UNDEFINED;
2601976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2602976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // We can match widgets with hosts and providers only after hosts
2603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // and providers for all users have been loaded since the widget
2604976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // host and provider can be in different user profiles.
2605976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        LoadedWidgetState loadedWidgets = new LoadedWidgetState(widget,
2606976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                hostTag, providerTag);
2607976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        outLoadedWidgets.add(loadedWidgets);
2608742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
2609742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2610742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } while (type != XmlPullParser.END_DOCUMENT);
2611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (NullPointerException
2612976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | NumberFormatException
2613976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | XmlPullParserException
2614976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | IOException
2615976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | IndexOutOfBoundsException e) {
2616742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Slog.w(TAG, "failed parsing " + e);
2617976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return -1;
2618742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2619742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2620976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return version;
2621976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2622742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void performUpgradeLocked(int fromVersion) {
262439d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        if (fromVersion < CURRENT_VERSION) {
2625976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.v(TAG, "Upgrading widget database from " + fromVersion + " to "
2626976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + CURRENT_VERSION);
262739d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        }
262839d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
262939d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        int version = fromVersion;
263039d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
263139d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        // Update 1: keyguard moved from package "android" to "com.android.keyguard"
263239d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        if (version == 0) {
2633976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId oldHostId = new HostId(Process.myUid(),
2634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    KEYGUARD_HOST_ID, OLD_KEYGUARD_HOST_PACKAGE);
2635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2636976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(oldHostId);
2637976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
2638976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int uid = getUidForPackage(NEW_KEYGUARD_HOST_PACKAGE,
2639976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        UserHandle.USER_OWNER);
2640976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (uid >= 0) {
2641976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    host.id = new HostId(uid, KEYGUARD_HOST_ID, NEW_KEYGUARD_HOST_PACKAGE);
264239d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                }
264339d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            }
2644976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
264539d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            version = 1;
264639d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        }
264739d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
264839d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        if (version != CURRENT_VERSION) {
264939d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            throw new IllegalStateException("Failed to upgrade widget database");
265039d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        }
265139d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller    }
265239d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
2653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static File getStateFile(int userId) {
2654976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return new File(Environment.getUserSystemDirectory(userId), STATE_FILENAME);
2655135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    }
2656135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
2657976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static AtomicFile getSavedStateFile(int userId) {
2658976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        File dir = Environment.getUserSystemDirectory(userId);
2659976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        File settingsFile = getStateFile(userId);
2660976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!settingsFile.exists() && userId == UserHandle.USER_OWNER) {
2661e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            if (!dir.exists()) {
2662e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani                dir.mkdirs();
2663e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            }
2664e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            // Migrate old data
2665976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            File oldFile = new File("/data/system/" + STATE_FILENAME);
2666e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            // Method doesn't throw an exception on failure. Ignore any errors
2667e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            // in moving the file (like non-existence)
2668e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            oldFile.renameTo(settingsFile);
2669742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2670742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        return new AtomicFile(settingsFile);
2671742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2672742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2673976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onUserStopped(int userId) {
2674976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
26756bd702538d90005add1cfc33746da19404090dc1Svet Ganov            boolean providersChanged = false;
26766bd702538d90005add1cfc33746da19404090dc1Svet Ganov            boolean crossProfileWidgetsChanged = false;
26776bd702538d90005add1cfc33746da19404090dc1Svet Ganov
2678976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove widgets that have both host and provider in the user.
2679976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int widgetCount = mWidgets.size();
2680976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = widgetCount - 1; i >= 0; i--) {
2681976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
2682976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2683976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean hostInUser = widget.host.getUserId() == userId;
2684976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean hasProvider = widget.provider != null;
2685976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean providerInUser = hasProvider && widget.provider.getUserId() == userId;
2686976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2687976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If both host and provider are in the user, just drop the widgets
2688976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // as we do not want to make host callbacks and provider broadcasts
2689976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // as the host and the provider will be killed.
2690976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (hostInUser && (!hasProvider || providerInUser)) {
2691976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    mWidgets.remove(i);
2692976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    widget.host.widgets.remove(widget);
2693976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    widget.host = null;
2694976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (hasProvider) {
2695976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.provider.widgets.remove(widget);
2696976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.provider = null;
2697976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
2698976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2700756901d82b41f50610a63b7cf4c7747a70f1f724Amith Yamasani
2701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove hosts and notify providers in other profiles.
2702976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int hostCount = mHosts.size();
2703976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = hostCount - 1; i >= 0; i--) {
2704976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Host host = mHosts.get(i);
2705976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (host.getUserId() == userId) {
27066bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    crossProfileWidgetsChanged |= !host.widgets.isEmpty();
2707976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    deleteHostLocked(host);
2708976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2710135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
2711976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove the providers and notify hosts in other profiles.
2712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerCount = mProviders.size();
2713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = providerCount - 1; i >= 0; i--) {
2714976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
2715976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() == userId) {
27166bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    crossProfileWidgetsChanged |= !provider.widgets.isEmpty();
27176bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    providersChanged = true;
2718976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    deleteProviderLocked(provider);
2719976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2720976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2721976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2722976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove grants for this user.
2723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int grantCount = mPackagesWithBindWidgetPermission.size();
2724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = grantCount - 1; i >= 0; i--) {
2725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> packageId = mPackagesWithBindWidgetPermission.valueAt(i);
2726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageId.first == userId) {
2727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    mPackagesWithBindWidgetPermission.removeAt(i);
2728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2729742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2731976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Take a note we no longer have state for this user.
2732c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            final int userIndex = mLoadedUserIds.indexOfKey(userId);
2733c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            if (userIndex >= 0) {
2734c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav                mLoadedUserIds.removeAt(userIndex);
2735742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
27367fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
2737976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove the widget id counter.
2738c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            final int nextIdIndex = mNextAppWidgetIds.indexOfKey(userId);
2739c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            if (nextIdIndex >= 0) {
2740c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav                mNextAppWidgetIds.removeAt(nextIdIndex);
2741c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            }
27426bd702538d90005add1cfc33746da19404090dc1Svet Ganov
27436bd702538d90005add1cfc33746da19404090dc1Svet Ganov            // Announce removed provider changes to all hosts in the group.
27446bd702538d90005add1cfc33746da19404090dc1Svet Ganov            if (providersChanged) {
27456bd702538d90005add1cfc33746da19404090dc1Svet Ganov                scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
27466bd702538d90005add1cfc33746da19404090dc1Svet Ganov            }
27476bd702538d90005add1cfc33746da19404090dc1Svet Ganov
27486bd702538d90005add1cfc33746da19404090dc1Svet Ganov            // Save state if removing a profile changed the group state.
27496bd702538d90005add1cfc33746da19404090dc1Svet Ganov            // Nothing will be saved if the group parent was removed.
27506bd702538d90005add1cfc33746da19404090dc1Svet Ganov            if (crossProfileWidgetsChanged) {
27516bd702538d90005add1cfc33746da19404090dc1Svet Ganov                saveGroupStateAsync(userId);
27526bd702538d90005add1cfc33746da19404090dc1Svet Ganov            }
2753976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2754742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2755742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2756a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung    /**
2757a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     * Updates all providers with the specified package names, and records any providers that were
2758a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     * pruned.
2759a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     *
2760a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     * @return whether any providers were updated
2761a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     */
2762976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean updateProvidersForPackageLocked(String packageName, int userId,
2763976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Set<ProviderId> removedProviders) {
27647fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        boolean providersUpdated = false;
2765976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2766976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        HashSet<ProviderId> keep = new HashSet<>();
2767742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2768976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setPackage(packageName);
2769976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<ResolveInfo> broadcastReceivers = queryIntentReceivers(intent, userId);
2770742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2771742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // add the missing ones and collect which ones to keep
2772742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
2773742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = 0; i < N; i++) {
2774742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            ResolveInfo ri = broadcastReceivers.get(i);
2775742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            ActivityInfo ai = ri.activityInfo;
2776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2777742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
2778742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                continue;
2779742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2780976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2781976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageName.equals(ai.packageName)) {
2782976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ProviderId providerId = new ProviderId(ai.applicationInfo.uid,
2783976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        new ComponentName(ai.packageName, ai.name));
2784976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2785976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = lookupProviderLocked(providerId);
2786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider == null) {
2787742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    if (addProviderLocked(ri)) {
2788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        keep.add(providerId);
27897fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                        providersUpdated = true;
2790742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
2791742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                } else {
2792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider parsed = parseProviderInfoXml(providerId, ri);
2793742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    if (parsed != null) {
2794976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        keep.add(providerId);
2795742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // Use the new AppWidgetProviderInfo.
2796976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        provider.info = parsed.info;
2797742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // If it's enabled
2798976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int M = provider.widgets.size();
2799742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        if (M > 0) {
2800976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int[] appWidgetIds = getWidgetIds(provider.widgets);
2801742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // Reschedule for the new updatePeriodMillis (don't worry about handling
2802742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // it specially if updatePeriodMillis didn't change because we just sent
2803742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // an update, and the next one will be updatePeriodMillis from now).
2804976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            cancelBroadcasts(provider);
2805976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            registerForBroadcastsLocked(provider, appWidgetIds);
2806742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // If it's currently showing, call back with the new
2807742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // AppWidgetProviderInfo.
2808742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            for (int j = 0; j < M; j++) {
2809976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Widget widget = provider.widgets.get(j);
2810976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                widget.views = null;
2811976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                scheduleNotifyProviderChangedLocked(widget);
2812742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            }
2813742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // Now that we've told the host, push out an update.
2814976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            sendUpdateIntentLocked(provider, appWidgetIds);
28157fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                            providersUpdated = true;
2816742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2817742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
2818742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2819742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2820742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2821742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2822742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // prune the ones we don't want to keep
2823976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        N = mProviders.size();
2824742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = N - 1; i >= 0; i--) {
2825976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2826976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageName.equals(provider.info.provider.getPackageName())
2827976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.getUserId() == userId
2828976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && !keep.contains(provider.id)) {
2829a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                if (removedProviders != null) {
2830976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    removedProviders.add(provider.id);
2831a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                }
2832976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                deleteProviderLocked(provider);
28337fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                providersUpdated = true;
2834742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2835742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
28367fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
28377fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        return providersUpdated;
2838742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2839742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2840976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) {
2841976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean removed = false;
2842976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2843976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int N = mProviders.size();
2844742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = N - 1; i >= 0; i--) {
2845976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2846976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (pkgName.equals(provider.info.provider.getPackageName())
2847976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.getUserId() == userId) {
2848976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                deleteProviderLocked(provider);
2849976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                removed = true;
2850742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2851742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2852742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2853742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // Delete the hosts for this package too
2854742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // By now, we have removed any AppWidgets that were in any hosts here,
2855742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // so we don't need to worry about sending DISABLE broadcasts to them.
2856742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        N = mHosts.size();
2857742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = N - 1; i >= 0; i--) {
2858742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Host host = mHosts.get(i);
2859976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (pkgName.equals(host.id.packageName)
2860976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && host.getUserId() == userId) {
2861742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                deleteHostLocked(host);
2862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                removed = true;
2863742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2864742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
28657fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
2866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return removed;
28677fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung    }
28687fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
2869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private String getCanonicalPackageName(String packageName, String className, int userId) {
2870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2871976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
28727fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung            try {
2873976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                AppGlobals.getPackageManager().getReceiverInfo(new ComponentName(packageName,
2874976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        className), 0, userId);
2875976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return packageName;
2876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
2877976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                String[] packageNames = mContext.getPackageManager()
2878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        .currentToCanonicalPackageNames(new String[]{packageName});
2879976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageNames != null && packageNames.length > 0) {
2880976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return packageNames[0];
28817fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                }
2882976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2883976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2884976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2885976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2886976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2887976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2889976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendBroadcastAsUser(Intent intent, UserHandle userHandle) {
2890976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
2892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.sendBroadcastAsUser(intent, userHandle);
2893976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2894976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2895976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2896976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2897976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2898976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void bindService(Intent intent, ServiceConnection connection,
2899976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            UserHandle userHandle) {
2900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long token = Binder.clearCallingIdentity();
2901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
2902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
2903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    userHandle);
2904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(token);
2906976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2909976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void unbindService(ServiceConnection connection) {
2910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long token = Binder.clearCallingIdentity();
2911976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
2912976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.unbindService(connection);
2913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(token);
2915976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2916976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
29186bd702538d90005add1cfc33746da19404090dc1Svet Ganov    @Override
29196bd702538d90005add1cfc33746da19404090dc1Svet Ganov    public void onCrossProfileWidgetProvidersChanged(int userId, List<String> packages) {
29206bd702538d90005add1cfc33746da19404090dc1Svet Ganov        final int parentId = mSecurityPolicy.getProfileParent(userId);
29216bd702538d90005add1cfc33746da19404090dc1Svet Ganov        // We care only if the white-listed package is in a profile of
29226bd702538d90005add1cfc33746da19404090dc1Svet Ganov        // the group parent as only the parent can add widgets from the
29236bd702538d90005add1cfc33746da19404090dc1Svet Ganov        // profile and not the other way around.
29246bd702538d90005add1cfc33746da19404090dc1Svet Ganov        if (parentId != userId) {
29256bd702538d90005add1cfc33746da19404090dc1Svet Ganov            synchronized (mLock) {
29266bd702538d90005add1cfc33746da19404090dc1Svet Ganov                boolean providersChanged = false;
29276bd702538d90005add1cfc33746da19404090dc1Svet Ganov
29286bd702538d90005add1cfc33746da19404090dc1Svet Ganov                final int packageCount = packages.size();
29296bd702538d90005add1cfc33746da19404090dc1Svet Ganov                for (int i = 0; i < packageCount; i++) {
29306bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    String packageName = packages.get(i);
29316bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    providersChanged |= updateProvidersForPackageLocked(packageName,
29326bd702538d90005add1cfc33746da19404090dc1Svet Ganov                            userId, null);
29336bd702538d90005add1cfc33746da19404090dc1Svet Ganov                }
29346bd702538d90005add1cfc33746da19404090dc1Svet Ganov
29356bd702538d90005add1cfc33746da19404090dc1Svet Ganov                if (providersChanged) {
29366bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    saveGroupStateAsync(userId);
29376bd702538d90005add1cfc33746da19404090dc1Svet Ganov                    scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
29386bd702538d90005add1cfc33746da19404090dc1Svet Ganov                }
29396bd702538d90005add1cfc33746da19404090dc1Svet Ganov            }
29406bd702538d90005add1cfc33746da19404090dc1Svet Ganov        }
29416bd702538d90005add1cfc33746da19404090dc1Svet Ganov    }
29426bd702538d90005add1cfc33746da19404090dc1Svet Ganov
2943976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class CallbackHandler extends Handler {
2944976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1;
2945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2;
2946976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_PROVIDERS_CHANGED = 3;
2947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_VIEW_DATA_CHANGED = 4;
2948976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public CallbackHandler(Looper looper) {
2950976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            super(looper, null, false);
2951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2952976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2953976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
2954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void handleMessage(Message message) {
2955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            switch (message.what) {
2956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_UPDATE_APP_WIDGET: {
2957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    RemoteViews views = (RemoteViews) args.arg3;
2961976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int appWidgetId = args.argi1;
2962976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2963976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views);
2965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2967976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_PROVIDER_CHANGED: {
2968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2970976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2971976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3;
2972976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int appWidgetId = args.argi1;
2973976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info);
2976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_PROVIDERS_CHANGED: {
2979976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2981976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2982976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyProvidersChanged(host, callbacks);
2985976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_VIEW_DATA_CHANGED: {
2988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int appWidgetId = args.argi1;
2992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int viewId = args.argi2;
2993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId);
2996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2997976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2998976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2999976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3000976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3001976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class SecurityPolicy {
3002976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
30038e1d299da27da534b508b1da51ebe351a689cefaSvetoslav        public boolean isEnabledGroupProfile(int profileId) {
3004976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = UserHandle.getCallingUserId();
30058e1d299da27da534b508b1da51ebe351a689cefaSvetoslav            return isParentOrProfile(parentId, profileId) && isProfileEnabled(profileId);
3006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3007976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3008976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int[] getEnabledGroupProfileIds(int userId) {
3009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = getGroupParent(userId);
3010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3011976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final List<UserInfo> profiles;
3012976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                profiles = mUserManager.getProfiles(parentId);
3015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int enabledProfileCount = 0;
3020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileCount = profiles.size();
3021976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < profileCount; i++) {
3022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (profiles.get(i).isEnabled()) {
3023976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    enabledProfileCount++;
3024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3025976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3026976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3027976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int enabledProfileIndex = 0;
3028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int[] profileIds = new int[enabledProfileCount];
3029976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < profileCount; i++) {
3030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                UserInfo profile = profiles.get(i);
3031976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (profile.isEnabled()) {
3032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    profileIds[enabledProfileIndex] = profile.getUserHandle().getIdentifier();
3033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    enabledProfileIndex++;
3034976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3035976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3036976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3037976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return profileIds;
3038976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3039976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3040976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void enforceServiceExistsAndRequiresBindRemoteViewsPermission(
3041976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ComponentName componentName, int userId) {
3042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3044976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ServiceInfo serviceInfo = mPackageManager.getServiceInfo(componentName,
3045976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        PackageManager.GET_PERMISSIONS, userId);
3046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (serviceInfo == null) {
3047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new SecurityException("Service " + componentName
3048976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + " not installed for user " + userId);
3049976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3050976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(serviceInfo.permission)) {
3051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new SecurityException("Service " + componentName
3052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + " in user " + userId + "does not require "
3053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + android.Manifest.permission.BIND_REMOTEVIEWS);
3054976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
3056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Local call - shouldn't happen.
3057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3059976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3060976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3061976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3062976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void enforceModifyAppWidgetBindPermissions(String packageName) {
3063976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.enforceCallingPermission(
3064976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
3065976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    "hasBindAppWidgetPermission packageName=" + packageName);
3066976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3067976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3068976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void enforceCallFromPackage(String packageName) {
30695771ad7bc7533f4a9bc72ac1ecabfdf6ca493b16Svet Ganov            mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
3070976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3071976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3072976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean hasCallerBindPermissionOrBindWhiteListedLocked(String packageName) {
3073976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3074976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.enforceCallingOrSelfPermission(
3075976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        android.Manifest.permission.BIND_APPWIDGET, null);
3076976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (SecurityException se) {
3077976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!isCallerBindAppWidgetWhiteListedLocked(packageName)) {
3078976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3079976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3080976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3081976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3082976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3083976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3084976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isCallerBindAppWidgetWhiteListedLocked(String packageName) {
3085976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int userId = UserHandle.getCallingUserId();
3086976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int packageUid = getUidForPackage(packageName, userId);
3087976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageUid < 0) {
3088976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("No package " + packageName
3089976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for user " + userId);
3090976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3091976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3092976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ensureGroupStateLoadedLocked(userId);
3093976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3094976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> packageId = Pair.create(userId, packageName);
3095976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (mPackagesWithBindWidgetPermission.contains(packageId)) {
3096976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3097976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3098976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3099976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3100976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3101976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3102976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3103976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean canAccessAppWidget(Widget widget, int uid, String packageName) {
3104976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isHostInPackageForUid(widget.host, uid, packageName)) {
3105976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Apps hosting the AppWidget have access to it.
3106976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3107976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3108976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isProviderInPackageForUid(widget.provider, uid, packageName)) {
3109976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Apps providing the AppWidget have access to it.
3110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3111976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3112976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isHostAccessingProvider(widget.host, widget.provider, uid, packageName)) {
3113976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Apps hosting the AppWidget get to bind to a remote view service in the provider.
3114976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3115976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3116985e566ceca9c11d2f740499053f37dfaeb9033dSvetoslav            final int userId = UserHandle.getUserId(uid);
3117985e566ceca9c11d2f740499053f37dfaeb9033dSvetoslav            if ((widget.host.getUserId() == userId || (widget.provider != null
3118985e566ceca9c11d2f740499053f37dfaeb9033dSvetoslav                    && widget.provider.getUserId() == userId))
3119985e566ceca9c11d2f740499053f37dfaeb9033dSvetoslav                && mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET)
3120976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    == PackageManager.PERMISSION_GRANTED) {
3121985e566ceca9c11d2f740499053f37dfaeb9033dSvetoslav                // Apps that run in the same user as either the host or the provider and
3122985e566ceca9c11d2f740499053f37dfaeb9033dSvetoslav                // have the bind widget permission have access to the widget.
3123976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3124976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3125976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3126976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3127976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3128976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isParentOrProfile(int parentId, int profileId) {
3129976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (parentId == profileId) {
3130976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3131976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3132976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return getProfileParent(profileId) == parentId;
3133976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3134976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3135976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isProviderInCallerOrInProfileAndWhitelListed(String packageName,
3136976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                int profileId) {
3137976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int callerId = UserHandle.getCallingUserId();
3138976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (profileId == callerId) {
3139976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3141976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = getProfileParent(profileId);
3142976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (parentId != callerId) {
3143976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3145976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return isProviderWhitelListed(packageName, profileId);
3146976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3147976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3148976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isProviderWhitelListed(String packageName, int profileId) {
3149976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
3150976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    DevicePolicyManagerInternal.class);
3151976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3152976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If the policy manager is not available on the device we deny it all.
3153976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (devicePolicyManager == null) {
3154976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3155976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3156976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3157976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            List<String> crossProfilePackages = devicePolicyManager
3158976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    .getCrossProfileWidgetProviders(profileId);
3159976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3160976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return crossProfilePackages.contains(packageName);
3161976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3162976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3163976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getProfileParent(int profileId) {
3164976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3165976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3166976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                UserInfo parent = mUserManager.getProfileParent(profileId);
3167976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (parent != null) {
3168976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return parent.getUserHandle().getIdentifier();
3169976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3170976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3171976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3172976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3173976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return UNKNOWN_USER_ID;
3174976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3175976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3176976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getGroupParent(int profileId) {
3177976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = mSecurityPolicy.getProfileParent(profileId);
3178976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return (parentId != UNKNOWN_USER_ID) ? parentId : profileId;
3179976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3180976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3181976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isHostInPackageForUid(Host host, int uid, String packageName) {
3182985e566ceca9c11d2f740499053f37dfaeb9033dSvetoslav            return host.id.uid == uid && host.id.packageName.equals(packageName);
3183976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3184976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3185976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isProviderInPackageForUid(Provider provider, int uid,
3186976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                String packageName) {
3187976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Packages providing the AppWidget have access to it.
3188976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return provider != null && provider.id.uid == uid
3189976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.id.componentName.getPackageName().equals(packageName);
3190976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3191976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3192976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isHostAccessingProvider(Host host, Provider provider, int uid,
3193976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                String packageName) {
3194976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // The host creates a package context to bind to remote views service in the provider.
3195976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return host.id.uid == uid && provider != null
3196976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.id.componentName.getPackageName().equals(packageName);
3197976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3198976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3199976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isProfileEnabled(int profileId) {
3200976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3201976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3202976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                UserInfo userInfo = mUserManager.getUserInfo(profileId);
3203976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (userInfo == null || !userInfo.isEnabled()) {
3204976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3205976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3206976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3207976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3208976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3209976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3210976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3211976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3212976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3213976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class Provider {
3214976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ProviderId id;
3215976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        AppWidgetProviderInfo info;
3216976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ArrayList<Widget> widgets = new ArrayList<>();
3217976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        PendingIntent broadcast;
3218976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
3219976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3220976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int tag = TAG_UNDEFINED; // for use while saving state (the index)
3221976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3222976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getUserId() {
3223976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return UserHandle.getUserId(id.uid);
3224976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3225976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3226976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isInPackageForUser(String packageName, int userId) {
3227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return getUserId() == userId
3228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && id.componentName.getPackageName().equals(packageName);
3229976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // is there an instance of this provider hosted by the given app?
3232976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean hostedByPackageForUser(String packageName, int userId) {
3233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = widgets.size();
3234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3235976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = widgets.get(i);
3236976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageName.equals(widget.host.id.packageName)
3237976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && widget.host.getUserId() == userId) {
3238976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3239976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3240976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3241976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3242976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3245976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3246976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "Provider{" + id + (zombie ? " Z" : "") + '}';
3247976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3248976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3249976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3250976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class ProviderId {
3251976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int uid;
3252976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final ComponentName componentName;
3253976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3254976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private ProviderId(int uid, ComponentName componentName) {
3255976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.uid = uid;
3256976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.componentName = componentName;
3257976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3258976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3259976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3260976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean equals(Object obj) {
3261976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (this == obj) {
3262976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3263976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3264976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (obj == null) {
3265976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3266976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (getClass() != obj.getClass()) {
3268976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3269976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3270976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId other = (ProviderId) obj;
3271976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (uid != other.uid)  {
3272976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3273976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3274976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (componentName == null) {
3275976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (other.componentName != null) {
3276976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3277976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3278976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (!componentName.equals(other.componentName)) {
3279976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3281976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3283976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3284976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int hashCode() {
3286976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int result = uid;
3287976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            result = 31 * result + ((componentName != null)
3288976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ? componentName.hashCode() : 0);
3289976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return result;
3290976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3291976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3292976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "ProviderId{user:" + UserHandle.getUserId(uid) + ", app:"
3295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + UserHandle.getAppId(uid) + ", cmp:" + componentName + '}';
3296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3297976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3298976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3299976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class Host {
3300976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        HostId id;
3301976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ArrayList<Widget> widgets = new ArrayList<>();
3302976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IAppWidgetHost callbacks;
3303976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
3304976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3305976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int tag = TAG_UNDEFINED; // for use while saving state (the index)
3306976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3307976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getUserId() {
3308976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return UserHandle.getUserId(id.uid);
3309976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3310976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3311976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isInPackageForUser(String packageName, int userId) {
3312976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return getUserId() == userId && id.packageName.equals(packageName);
3313976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3314976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3315976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean hostsPackageForUser(String pkg, int userId) {
3316976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = widgets.size();
3317976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3318976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = widgets.get(i).provider;
3319976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider != null && provider.getUserId() == userId && provider.info != null
3320976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && pkg.equals(provider.info.provider.getPackageName())) {
3321976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3322976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3323976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3324976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3325976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3326976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3327976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3328976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3329976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "Host{" + id + (zombie ? " Z" : "") + '}';
3330976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3331976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3332976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3333976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class HostId {
3334976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int uid;
3335976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostId;
3336976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final String packageName;
3337976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3338976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public HostId(int uid, int hostId, String packageName) {
3339976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.uid = uid;
3340976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.hostId = hostId;
3341976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.packageName = packageName;
3342976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3343976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3344976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean equals(Object obj) {
3346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (this == obj) {
3347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (obj == null) {
3350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3352976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (getClass() != obj.getClass()) {
3353976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3354976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3355976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId other = (HostId) obj;
3356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (uid != other.uid)  {
3357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3359976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (hostId != other.hostId) {
3360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3362976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageName == null) {
3363976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (other.packageName != null) {
3364976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3365976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3366976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (!packageName.equals(other.packageName)) {
3367976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3368976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3371976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3372976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int hashCode() {
3374976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int result = uid;
3375976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            result = 31 * result + hostId;
3376976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            result = 31 * result + ((packageName != null)
3377976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ? packageName.hashCode() : 0);
3378976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return result;
3379976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3380976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3381976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3382976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3383976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "HostId{user:" + UserHandle.getUserId(uid) + ", app:"
3384976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + UserHandle.getAppId(uid) + ", hostId:" + hostId
3385976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + ", pkg:" + packageName + '}';
3386976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3387976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3388976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3389976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class Widget {
3390976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int appWidgetId;
3391976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int restoredId;  // tracking & remapping any restored state
3392976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider;
3393976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        RemoteViews views;
3394976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Bundle options;
3395976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Host host;
3396976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3397976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3398976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3399976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
3400976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3401976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3402976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3403976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    /**
3404976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This
3405976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * needs to be a static inner class since a reference to the ServiceConnection is held globally
3406976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * and may lead us to leak AppWidgetService instances (if there were more than one).
3407976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     */
3408976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class ServiceConnectionProxy implements ServiceConnection {
3409976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final IRemoteViewsAdapterConnection mConnectionCb;
3410976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3411976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ServiceConnectionProxy(IBinder connectionCb) {
3412976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mConnectionCb = IRemoteViewsAdapterConnection.Stub
3413976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    .asInterface(connectionCb);
3414976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3415976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void onServiceConnected(ComponentName name, IBinder service) {
3417976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3418976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mConnectionCb.onServiceConnected(service);
3419976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
3420976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Error passing service interface", re);
3421976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3422976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3424976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void onServiceDisconnected(ComponentName name) {
3425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            disconnect();
3426976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3427976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3428976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void disconnect() {
3429976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3430976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mConnectionCb.onServiceDisconnected();
3431976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
3432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Error clearing service interface", re);
3433976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3434976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3435976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3436976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3437976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private class LoadedWidgetState {
3438976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final Widget widget;
3439976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostTag;
3440976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int providerTag;
3441976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3442976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public LoadedWidgetState(Widget widget, int hostTag, int providerTag) {
3443976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.widget = widget;
3444976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.hostTag = hostTag;
3445976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.providerTag = providerTag;
3446976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3447976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3448976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3449976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class SaveStateRunnable implements Runnable {
3450976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int mUserId;
3451976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3452976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public SaveStateRunnable(int userId) {
3453976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mUserId = userId;
3454976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3455976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3456976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3457976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void run() {
3458976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3459976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ensureGroupStateLoadedLocked(mUserId);
3460976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveStateLocked(mUserId);
3461976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3462976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3463976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3464976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3465976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    /**
3466976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * This class encapsulates the backup and restore logic for a user group state.
3467976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     */
3468976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class BackupRestoreController {
3469976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private static final String TAG = "BackupRestoreController";
3470976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3471976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private static final boolean DEBUG = true;
3472976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3473976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Version of backed-up widget state.
3474976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private static final int WIDGET_STATE_VERSION = 2;
3475976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3476976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We need to make sure to wipe the pre-restore widget state only once for
3477976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // a given package.  Keep track of what we've done so far here; the list is
3478976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // cleared at the start of every system restore pass, but preserved through
3479976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // any install-time restore operations.
3480976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final HashSet<String> mPrunedApps = new HashSet<>();
3481976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3482976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final HashMap<Provider, ArrayList<RestoreUpdateRecord>> mUpdatesByProvider =
3483976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                new HashMap<>();
3484976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost =
3485976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                new HashMap<>();
3486976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3487976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public List<String> getWidgetParticipants(int userId) {
3488976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3489976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Getting widget participants for user: " + userId);
3490976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3491976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3492976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HashSet<String> packages = new HashSet<>();
3493976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3494976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int N = mWidgets.size();
3495976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (int i = 0; i < N; i++) {
3496976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Widget widget = mWidgets.get(i);
3497976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3498976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // Skip cross-user widgets.
3499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (!isProviderAndHostInUser(widget, userId)) {
3500976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        continue;
3501976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3502976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3503976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    packages.add(widget.host.id.packageName);
3504976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = widget.provider;
3505976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (provider != null) {
3506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        packages.add(provider.id.componentName.getPackageName());
3507976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3508976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3510976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return new ArrayList<>(packages);
3511976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3512976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3513976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public byte[] getWidgetState(String backedupPackage, int userId) {
3514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Getting widget state for user: " + userId);
3516976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3517976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3518976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ByteArrayOutputStream stream = new ByteArrayOutputStream();
3519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Preflight: if this app neither hosts nor provides any live widgets
3521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // we have no work to do.
3522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!packageNeedsWidgetBackupLocked(backedupPackage, userId)) {
3523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return null;
3524976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3525976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3526976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                try {
3527976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    XmlSerializer out = new FastXmlSerializer();
3528976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.setOutput(stream, "utf-8");
3529976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.startDocument(null, true);
3530976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.startTag(null, "ws");      // widget state
3531976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.attribute(null, "version", String.valueOf(WIDGET_STATE_VERSION));
3532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.attribute(null, "pkg", backedupPackage);
3533976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3534976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // Remember all the providers that are currently hosted or published
3535976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // by this package: that is, all of the entities related to this app
3536976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // which will need to be told about id remapping.
3537976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int index = 0;
3538976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int N = mProviders.size();
3539976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < N; i++) {
3540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Provider provider = mProviders.get(i);
3541976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3542976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (!provider.widgets.isEmpty()
3543976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                && (provider.isInPackageForUser(backedupPackage, userId)
3544976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                || provider.hostedByPackageForUser(backedupPackage, userId))) {
3545976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.tag = index;
3546976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            serializeProvider(out, provider);
3547976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            index++;
3548976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3549976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3550976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3551976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    N = mHosts.size();
3552976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    index = 0;
3553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < N; i++) {
3554976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Host host = mHosts.get(i);
3555976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3556976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (!host.widgets.isEmpty()
3557976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                && (host.isInPackageForUser(backedupPackage, userId)
3558976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                || host.hostsPackageForUser(backedupPackage, userId))) {
3559976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            host.tag = index;
3560976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            serializeHost(out, host);
3561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            index++;
3562976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3563976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3564976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3565976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // All widget instances involving this package,
3566976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // either as host or as provider
3567976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    N = mWidgets.size();
3568976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < N; i++) {
3569976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Widget widget = mWidgets.get(i);
3570976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3571976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Provider provider = widget.provider;
3572976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (widget.host.isInPackageForUser(backedupPackage, userId)
3573976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                || (provider != null
3574976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                &&  provider.isInPackageForUser(backedupPackage, userId))) {
3575976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            serializeAppWidget(out, widget);
3576976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3577976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3578976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3579976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.endTag(null, "ws");
3580976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.endDocument();
3581976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } catch (IOException e) {
3582976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.w(TAG, "Unable to save widget state for " + backedupPackage);
3583976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return null;
3584976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3585976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3586976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3587976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return stream.toByteArray();
3588976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3589976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3590976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void restoreStarting(int userId) {
3591976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3592976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Restore starting for user: " + userId);
3593976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3594976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3595976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3596976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // We're starting a new "system" restore operation, so any widget restore
3597976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // state that we see from here on is intended to replace the current
3598976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // widget configuration of any/all of the affected apps.
3599976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPrunedApps.clear();
3600976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByProvider.clear();
3601976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByHost.clear();
3602976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3604976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3605976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void restoreWidgetState(String packageName, byte[] restoredState, int userId) {
3606976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3607976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Restoring widget state for user:" + userId
3608976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " package: " + packageName);
3609976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3610976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ByteArrayInputStream stream = new ByteArrayInputStream(restoredState);
3612976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3613976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Providers mentioned in the widget dataset by ordinal
3614976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ArrayList<Provider> restoredProviders = new ArrayList<>();
3615976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3616976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Hosts mentioned in the widget dataset by ordinal
3617976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ArrayList<Host> restoredHosts = new ArrayList<>();
3618976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3619976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                XmlPullParser parser = Xml.newPullParser();
3620976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                parser.setInput(stream, null);
3621976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3622976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                synchronized (mLock) {
3623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int type;
3624976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    do {
3625976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        type = parser.next();
3626976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (type == XmlPullParser.START_TAG) {
3627976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final String tag = parser.getName();
3628976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            if ("ws".equals(tag)) {
3629976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String version = parser.getAttributeValue(null, "version");
3630976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3631976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                final int versionNumber = Integer.parseInt(version);
3632976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (versionNumber > WIDGET_STATE_VERSION) {
3633976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.w(TAG, "Unable to process state version " + version);
3634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    return;
3635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3636976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3637976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // TODO: fix up w.r.t. canonical vs current package names
3638976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String pkg = parser.getAttributeValue(null, "pkg");
3639976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (!packageName.equals(pkg)) {
3640976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.w(TAG, "Package mismatch in ws");
3641976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    return;
3642976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3643976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            } else if ("p".equals(tag)) {
3644976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String pkg = parser.getAttributeValue(null, "pkg");
3645976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String cl = parser.getAttributeValue(null, "cl");
3646976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3647976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // hostedProviders index will match 'p' attribute in widget's
3648976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // entry in the xml file being restored
3649976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // If there's no live entry for this provider, add an inactive one
3650976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // so that widget IDs referring to them can be properly allocated
3651976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3652976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // Backup and resotre only for the parent profile.
3653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                ComponentName componentName = new ComponentName(pkg, cl);
3654976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3655976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Provider p = findProviderLocked(componentName, userId);
3656976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (p == null) {
3657976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p = new Provider();
3658976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.id = new ProviderId(UNKNOWN_UID, componentName);
3659976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.info = new AppWidgetProviderInfo();
3660976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.info.provider = componentName;
3661976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.zombie = true;
3662976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    mProviders.add(p);
3663976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3664976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3665976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   provider " + p.id);
3666976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3667976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                restoredProviders.add(p);
3668976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            } else if ("h".equals(tag)) {
3669976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // The host app may not yet exist on the device.  If it's here we
3670976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // just use the existing Host entry, otherwise we create a
3671976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // placeholder whose uid will be fixed up at PACKAGE_ADDED time.
3672976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String pkg = parser.getAttributeValue(null, "pkg");
3673976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3674976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                final int uid = getUidForPackage(pkg, userId);
3675976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                final int hostId = Integer.parseInt(
3676976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        parser.getAttributeValue(null, "id"), 16);
3677976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3678976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                HostId id = new HostId(uid, hostId, pkg);
3679976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Host h = lookupOrAddHostLocked(id);
3680976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                restoredHosts.add(h);
3681976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3682976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3683976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   host[" + restoredHosts.size()
3684976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            + "]: {" + h.id + "}");
3685976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3686976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            } else if ("g".equals(tag)) {
3687976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                int restoredId = Integer.parseInt(
3688976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        parser.getAttributeValue(null, "id"), 16);
3689976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                int hostIndex = Integer.parseInt(
3690976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        parser.getAttributeValue(null, "h"), 16);
3691976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Host host = restoredHosts.get(hostIndex);
3692976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Provider p = null;
3693976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String prov = parser.getAttributeValue(null, "p");
3694976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (prov != null) {
3695976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    // could have been null if the app had allocated an id
3696976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    // but not yet established a binding under that id
3697976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    int which = Integer.parseInt(prov, 16);
3698976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p = restoredProviders.get(which);
3699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3700976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // We'll be restoring widget state for both the host and
3702976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // provider sides of this widget ID, so make sure we are
3703976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // beginning from a clean slate on both fronts.
3704976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                pruneWidgetStateLocked(host.id.packageName, userId);
3705976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (p != null) {
3706976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    pruneWidgetStateLocked(p.id.componentName.getPackageName(),
3707976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            userId);
3708976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3710976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // Have we heard about this ancestral widget instance before?
3711976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Widget id = findRestoredWidgetLocked(restoredId, host, p);
3712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (id == null) {
3713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id = new Widget();
3714976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.appWidgetId = incrementAndGetAppWidgetIdLocked(userId);
3715976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.restoredId = restoredId;
3716976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.options = parseWidgetIdOptions(parser);
3717976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.host = host;
3718976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.host.widgets.add(id);
3719976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.provider = p;
3720976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    if (id.provider != null) {
3721976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        id.provider.widgets.add(id);
3722976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    }
3723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    if (DEBUG) {
3724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        Slog.i(TAG, "New restored id " + restoredId
3725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                                + " now " + id);
3726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    }
3727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    mWidgets.add(id);
3728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3729976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (id.provider.info != null) {
3730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    stashProviderRestoreUpdateLocked(id.provider,
3731976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            restoredId, id.appWidgetId);
3732976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                } else {
3733976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.w(TAG, "Missing provider for restored widget " + id);
3734976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3735976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                stashHostRestoreUpdateLocked(id.host, restoredId, id.appWidgetId);
3736976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3737976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3738976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   instance: " + restoredId
3739976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            + " -> " + id.appWidgetId
3740976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            + " :: p=" + id.provider);
3741976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3742976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
3743976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3744976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    } while (type != XmlPullParser.END_DOCUMENT);
3745976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3746976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // We've updated our own bookkeeping.  We'll need to notify the hosts and
3747976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // providers about the changes, but we can't do that yet because the restore
3748976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // target is not necessarily fully live at this moment.  Set aside the
3749976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // information for now; the backup manager will call us once more at the
3750976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // end of the process when all of the targets are in a known state, and we
3751976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // will update at that point.
3752976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3753976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (XmlPullParserException | IOException e) {
3754976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Unable to restore widget state for " + packageName);
3755976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3756976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveGroupStateAsync(userId);
3757976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3758976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3759976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3760976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Called once following the conclusion of a restore operation.  This is when we
3761976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // send out updates to apps involved in widget-state restore telling them about
3762976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // the new widget ID space.
3763976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void restoreFinished(int userId) {
3764976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3765976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "restoreFinished for " + userId);
3766976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3767976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3768976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final UserHandle userHandle = new UserHandle(userId);
3769976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3770976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Build the providers' broadcasts and send them off
3771976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries
3772976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        = mUpdatesByProvider.entrySet();
3773976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) {
3774976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // For each provider there's a list of affected IDs
3775976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = e.getKey();
3776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ArrayList<RestoreUpdateRecord> updates = e.getValue();
3777976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int pending = countPendingUpdates(updates);
3778976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3779976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "Provider " + provider + " pending: " + pending);
3780976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3781976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (pending > 0) {
3782976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        int[] oldIds = new int[pending];
3783976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        int[] newIds = new int[pending];
3784976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int N = updates.size();
3785976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        int nextPending = 0;
3786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        for (int i = 0; i < N; i++) {
3787976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            RestoreUpdateRecord r = updates.get(i);
3788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            if (!r.notified) {
3789976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                r.notified = true;
3790976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                oldIds[nextPending] = r.oldId;
3791976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                newIds[nextPending] = r.newId;
3792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                nextPending++;
3793976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3794976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   " + r.oldId + " => " + r.newId);
3795976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3796976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
3797976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3798976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        sendWidgetRestoreBroadcastLocked(
3799976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                AppWidgetManager.ACTION_APPWIDGET_RESTORED,
3800976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                provider, null, oldIds, newIds, userHandle);
3801976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3802976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3803976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3804976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // same thing per host
3805976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries
3806976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        = mUpdatesByHost.entrySet();
3807976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) {
3808976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = e.getKey();
3809976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (host.id.uid != UNKNOWN_UID) {
3810976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ArrayList<RestoreUpdateRecord> updates = e.getValue();
3811976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int pending = countPendingUpdates(updates);
3812976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (DEBUG) {
3813976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            Slog.i(TAG, "Host " + host + " pending: " + pending);
3814976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3815976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (pending > 0) {
3816976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int[] oldIds = new int[pending];
3817976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int[] newIds = new int[pending];
3818976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int N = updates.size();
3819976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int nextPending = 0;
3820976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            for (int i = 0; i < N; i++) {
3821976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                RestoreUpdateRecord r = updates.get(i);
3822976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (!r.notified) {
3823976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    r.notified = true;
3824976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    oldIds[nextPending] = r.oldId;
3825976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    newIds[nextPending] = r.newId;
3826976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    nextPending++;
3827976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    if (DEBUG) {
3828976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        Slog.i(TAG, "   " + r.oldId + " => " + r.newId);
3829976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    }
3830976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3831976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
3832976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            sendWidgetRestoreBroadcastLocked(
3833976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED,
3834976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    null, host, oldIds, newIds, userHandle);
3835976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3836976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3837976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3838976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3839976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3840976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3841976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private Provider findProviderLocked(ComponentName componentName, int userId) {
3842976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerCount = mProviders.size();
3843976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < providerCount; i++) {
3844976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
3845976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() == userId
3846976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && provider.id.componentName.equals(componentName)) {
3847976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return provider;
3848976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3849976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3850976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
3851976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3852976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3853976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private Widget findRestoredWidgetLocked(int restoredId, Host host, Provider p) {
3854976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3855976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Find restored widget: id=" + restoredId
3856976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " host=" + host + " provider=" + p);
3857976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3858976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3859976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (p == null || host == null) {
3860976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return null;
3861976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3863976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mWidgets.size();
3864976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3865976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
3866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget.restoredId == restoredId
3867976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && widget.host.id.equals(host.id)
3868976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && widget.provider.id.equals(p.id)) {
3869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "   Found at " + i + " : " + widget);
3871976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3872976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return widget;
3873976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3874976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3875976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
3876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3877976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean packageNeedsWidgetBackupLocked(String packageName, int userId) {
3879976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int N = mWidgets.size();
3880976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3881976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
3882976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3883976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Skip cross-user widgets.
3884976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!isProviderAndHostInUser(widget, userId)) {
3885976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
3886976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3887976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget.host.isInPackageForUser(packageName, userId)) {
3889976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // this package is hosting widgets, so it knows widget IDs.
3890976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3893976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = widget.provider;
3894976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider != null && provider.isInPackageForUser(packageName, userId)) {
3895976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // someone is hosting this app's widgets, so it knows widget IDs.
3896976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3897976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3898976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3899976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId) {
3903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<RestoreUpdateRecord> r = mUpdatesByProvider.get(provider);
3904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (r == null) {
3905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                r = new ArrayList<>();
3906976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByProvider.put(provider, r);
3907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
3908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // don't duplicate
3909976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (alreadyStashed(r, oldId, newId)) {
3910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3911976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "ID remap " + oldId + " -> " + newId
3912976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                + " already stashed for " + provider);
3913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return;
3915976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3916976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            r.add(new RestoreUpdateRecord(oldId, newId));
3918976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3919976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3920976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean alreadyStashed(ArrayList<RestoreUpdateRecord> stash,
3921976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int oldId, final int newId) {
3922976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = stash.size();
3923976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3924976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                RestoreUpdateRecord r = stash.get(i);
3925976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (r.oldId == oldId && r.newId == newId) {
3926976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3927976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3928976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3929976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3930976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3931976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3932976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void stashHostRestoreUpdateLocked(Host host, int oldId, int newId) {
3933976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<RestoreUpdateRecord> r = mUpdatesByHost.get(host);
3934976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (r == null) {
3935976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                r = new ArrayList<>();
3936976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByHost.put(host, r);
3937976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
3938976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (alreadyStashed(r, oldId, newId)) {
3939976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3940976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "ID remap " + oldId + " -> " + newId
3941976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                + " already stashed for " + host);
3942976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3943976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return;
3944976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3946976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            r.add(new RestoreUpdateRecord(oldId, newId));
3947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3948976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void sendWidgetRestoreBroadcastLocked(String action, Provider provider,
3950976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Host host, int[] oldIds, int[] newIds, UserHandle userHandle) {
3951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Intent intent = new Intent(action);
3952976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, oldIds);
3953976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, newIds);
3954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider != null) {
3955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.setComponent(provider.info.provider);
3956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendBroadcastAsUser(intent, userHandle);
3957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
3959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.setComponent(null);
3960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.setPackage(host.id.packageName);
3961976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.putExtra(AppWidgetManager.EXTRA_HOST_ID, host.id.hostId);
3962976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendBroadcastAsUser(intent, userHandle);
3963976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We're restoring widget state for 'pkg', so we start by wiping (a) all widget
3967976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // instances that are hosted by that app, and (b) all instances in other hosts
3968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // for which 'pkg' is the provider.  We assume that we'll be restoring all of
3969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // these hosts & providers, so will be reconstructing a correct live state.
3970976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void pruneWidgetStateLocked(String pkg, int userId) {
3971976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!mPrunedApps.contains(pkg)) {
3972976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (DEBUG) {
3973976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.i(TAG, "pruning widget state for restoring package " + pkg);
3974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (int i = mWidgets.size() - 1; i >= 0; i--) {
3976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Widget widget = mWidgets.get(i);
3977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = widget.host;
3979976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = widget.provider;
3980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3981976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (host.hostsPackageForUser(pkg, userId)
3982976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            || (provider != null && provider.isInPackageForUser(pkg, userId))) {
3983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // 'pkg' is either the host or the provider for this instances,
3984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // so we tear it down in anticipation of it (possibly) being
3985976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // reconstructed due to the restore
3986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        host.widgets.remove(widget);
3987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        provider.widgets.remove(widget);
3988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        unbindAppWidgetRemoteViewsServicesLocked(widget);
3989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mWidgets.remove(i);
3990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPrunedApps.add(pkg);
3993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
3994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (DEBUG) {
3995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.i(TAG, "already pruned " + pkg + ", continuing normally");
3996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3997976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3998976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3999976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4000976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isProviderAndHostInUser(Widget widget, int userId) {
4001976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Backup only widgets hosted or provided by the owner profile.
4002976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return widget.host.getUserId() == userId && (widget.provider == null
4003976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    || widget.provider.getUserId() == userId);
4004976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
4005976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private Bundle parseWidgetIdOptions(XmlPullParser parser) {
4007976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Bundle options = new Bundle();
4008976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String minWidthString = parser.getAttributeValue(null, "min_width");
4009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (minWidthString != null) {
4010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
4011976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(minWidthString, 16));
4012976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String minHeightString = parser.getAttributeValue(null, "min_height");
4014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (minHeightString != null) {
4015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
4016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(minHeightString, 16));
4017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String maxWidthString = parser.getAttributeValue(null, "max_width");
4019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (maxWidthString != null) {
4020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
4021976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(maxWidthString, 16));
4022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4023976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String maxHeightString = parser.getAttributeValue(null, "max_height");
4024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (maxHeightString != null) {
4025976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
4026976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(maxHeightString, 16));
4027976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String categoryString = parser.getAttributeValue(null, "host_category");
4029976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (categoryString != null) {
4030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
4031976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(categoryString, 16));
4032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return options;
4034976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
4035976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4036976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private int countPendingUpdates(ArrayList<RestoreUpdateRecord> updates) {
4037976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int pending = 0;
4038976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = updates.size();
4039976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
4040976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                RestoreUpdateRecord r = updates.get(i);
4041976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!r.notified) {
4042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    pending++;
4043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
4044976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4045976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return pending;
4046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
4047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4048976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Accumulate a list of updates that affect the given provider for a final
4049976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // coalesced notification broadcast once restore is over.
4050976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private class RestoreUpdateRecord {
4051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public int oldId;
4052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public int newId;
4053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public boolean notified;
4054976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public RestoreUpdateRecord(int theOldId, int theNewId) {
4056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                oldId = theOldId;
4057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newId = theNewId;
4058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                notified = false;
40597fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung            }
40607fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        }
4061742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
40629ce72731f22caa07d90dcd016c6441bfeb90225cNick Kralevich}
4063