Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License |
| 15 | */ |
| 16 | package com.android.systemui.qs.external; |
| 17 | |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 18 | import android.content.BroadcastReceiver; |
| 19 | import android.content.ComponentName; |
| 20 | import android.content.Context; |
| 21 | import android.content.Intent; |
| 22 | import android.content.IntentFilter; |
Gus Prevas | ab33679 | 2018-11-14 13:52:20 -0500 | [diff] [blame] | 23 | import android.content.ServiceConnection; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 24 | import android.content.pm.PackageManager; |
| 25 | import android.content.pm.ServiceInfo; |
| 26 | import android.net.Uri; |
Jason Monk | ee68fd8 | 2016-06-23 13:12:23 -0400 | [diff] [blame] | 27 | import android.os.Binder; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 28 | import android.os.Handler; |
| 29 | import android.os.IBinder; |
| 30 | import android.os.RemoteException; |
| 31 | import android.os.UserHandle; |
Jason Monk | fe8f682 | 2015-12-21 15:12:01 -0500 | [diff] [blame] | 32 | import android.service.quicksettings.IQSService; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 33 | import android.service.quicksettings.IQSTileService; |
| 34 | import android.service.quicksettings.Tile; |
Jason Monk | 97d2272 | 2016-04-07 11:41:47 -0400 | [diff] [blame] | 35 | import android.service.quicksettings.TileService; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 36 | import android.util.ArraySet; |
| 37 | import android.util.Log; |
Gus Prevas | ab33679 | 2018-11-14 13:52:20 -0500 | [diff] [blame] | 38 | |
| 39 | import androidx.annotation.VisibleForTesting; |
Jason Monk | ee68fd8 | 2016-06-23 13:12:23 -0400 | [diff] [blame] | 40 | |
Fabian Kozynski | 5ca7a51 | 2019-10-16 19:56:11 +0000 | [diff] [blame] | 41 | import com.android.systemui.broadcast.BroadcastDispatcher; |
| 42 | |
Narayan Kamath | 607223f | 2018-02-19 14:09:02 +0000 | [diff] [blame] | 43 | import java.util.Objects; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 44 | import java.util.Set; |
| 45 | |
| 46 | /** |
| 47 | * Manages the lifecycle of a TileService. |
| 48 | * <p> |
| 49 | * Will keep track of all calls on the IQSTileService interface and will relay those calls to the |
| 50 | * TileService as soon as it is bound. It will only bind to the service when it is allowed to |
| 51 | * ({@link #setBindService(boolean)}) and when the service is available. |
| 52 | */ |
| 53 | public class TileLifecycleManager extends BroadcastReceiver implements |
| 54 | IQSTileService, ServiceConnection, IBinder.DeathRecipient { |
| 55 | public static final boolean DEBUG = false; |
| 56 | |
| 57 | private static final String TAG = "TileLifecycleManager"; |
| 58 | |
| 59 | private static final int MSG_ON_ADDED = 0; |
| 60 | private static final int MSG_ON_REMOVED = 1; |
| 61 | private static final int MSG_ON_CLICK = 2; |
Jason Monk | 9429513 | 2016-01-12 11:27:02 -0500 | [diff] [blame] | 62 | private static final int MSG_ON_UNLOCK_COMPLETE = 3; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 63 | |
| 64 | // Bind retry control. |
| 65 | private static final int MAX_BIND_RETRIES = 5; |
Geoffrey Pitsch | ebee1a3 | 2016-09-09 13:04:12 -0400 | [diff] [blame] | 66 | private static final int DEFAULT_BIND_RETRY_DELAY = 1000; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 67 | |
Jason Monk | baade75 | 2016-08-25 15:57:14 -0400 | [diff] [blame] | 68 | // Shared prefs that hold tile lifecycle info. |
| 69 | private static final String TILES = "tiles_prefs"; |
| 70 | |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 71 | private final Context mContext; |
| 72 | private final Handler mHandler; |
| 73 | private final Intent mIntent; |
| 74 | private final UserHandle mUser; |
Jason Monk | ee68fd8 | 2016-06-23 13:12:23 -0400 | [diff] [blame] | 75 | private final IBinder mToken = new Binder(); |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 76 | private final PackageManagerAdapter mPackageManagerAdapter; |
Fabian Kozynski | 5ca7a51 | 2019-10-16 19:56:11 +0000 | [diff] [blame] | 77 | private final BroadcastDispatcher mBroadcastDispatcher; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 78 | |
| 79 | private Set<Integer> mQueuedMessages = new ArraySet<>(); |
| 80 | private QSTileServiceWrapper mWrapper; |
| 81 | private boolean mListening; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 82 | private IBinder mClickBinder; |
| 83 | |
| 84 | private int mBindTryCount; |
Geoffrey Pitsch | ebee1a3 | 2016-09-09 13:04:12 -0400 | [diff] [blame] | 85 | private int mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 86 | private boolean mBound; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 87 | boolean mReceiverRegistered; |
Jason Monk | 51c444b | 2016-01-06 16:32:29 -0500 | [diff] [blame] | 88 | private boolean mUnbindImmediate; |
Jason Monk | 624cbe2 | 2016-05-02 10:42:17 -0400 | [diff] [blame] | 89 | private TileChangeListener mChangeListener; |
Jason Monk | 6d21e0d | 2016-05-25 11:37:47 -0400 | [diff] [blame] | 90 | // Return value from bindServiceAsUser, determines whether safe to call unbind. |
| 91 | private boolean mIsBound; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 92 | |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 93 | public TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile, |
Fabian Kozynski | 5ca7a51 | 2019-10-16 19:56:11 +0000 | [diff] [blame] | 94 | Intent intent, UserHandle user, BroadcastDispatcher broadcastDispatcher) { |
| 95 | this(handler, context, service, tile, intent, user, new PackageManagerAdapter(context), |
| 96 | broadcastDispatcher); |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | @VisibleForTesting |
| 100 | TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile, |
Fabian Kozynski | 5ca7a51 | 2019-10-16 19:56:11 +0000 | [diff] [blame] | 101 | Intent intent, UserHandle user, PackageManagerAdapter packageManagerAdapter, |
| 102 | BroadcastDispatcher broadcastDispatcher) { |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 103 | mContext = context; |
| 104 | mHandler = handler; |
| 105 | mIntent = intent; |
Jason Monk | a3453b8b | 2016-06-17 12:42:59 -0400 | [diff] [blame] | 106 | mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder()); |
Jason Monk | ee68fd8 | 2016-06-23 13:12:23 -0400 | [diff] [blame] | 107 | mIntent.putExtra(TileService.EXTRA_TOKEN, mToken); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 108 | mUser = user; |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 109 | mPackageManagerAdapter = packageManagerAdapter; |
Fabian Kozynski | 5ca7a51 | 2019-10-16 19:56:11 +0000 | [diff] [blame] | 110 | mBroadcastDispatcher = broadcastDispatcher; |
Jason Monk | 1ffa11b | 2016-03-08 14:44:23 -0500 | [diff] [blame] | 111 | if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 112 | } |
| 113 | |
Jason Monk | fe8f682 | 2015-12-21 15:12:01 -0500 | [diff] [blame] | 114 | public ComponentName getComponent() { |
| 115 | return mIntent.getComponent(); |
| 116 | } |
| 117 | |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 118 | public boolean hasPendingClick() { |
| 119 | synchronized (mQueuedMessages) { |
| 120 | return mQueuedMessages.contains(MSG_ON_CLICK); |
| 121 | } |
| 122 | } |
| 123 | |
Geoffrey Pitsch | ebee1a3 | 2016-09-09 13:04:12 -0400 | [diff] [blame] | 124 | public void setBindRetryDelay(int delayMs) { |
| 125 | mBindRetryDelay = delayMs; |
| 126 | } |
| 127 | |
Jason Monk | 97d2272 | 2016-04-07 11:41:47 -0400 | [diff] [blame] | 128 | public boolean isActiveTile() { |
| 129 | try { |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 130 | ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(), |
Jason Monk | 97d2272 | 2016-04-07 11:41:47 -0400 | [diff] [blame] | 131 | PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA); |
| 132 | return info.metaData != null |
| 133 | && info.metaData.getBoolean(TileService.META_DATA_ACTIVE_TILE, false); |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 134 | } catch (PackageManager.NameNotFoundException e) { |
Jason Monk | 97d2272 | 2016-04-07 11:41:47 -0400 | [diff] [blame] | 135 | return false; |
| 136 | } |
| 137 | } |
| 138 | |
Jason Monk | 51c444b | 2016-01-06 16:32:29 -0500 | [diff] [blame] | 139 | /** |
Fabian Kozynski | 05843f0 | 2019-06-28 13:19:57 -0400 | [diff] [blame] | 140 | * Determines whether the associated TileService is a Boolean Tile. |
| 141 | * |
| 142 | * @return true if {@link TileService#META_DATA_BOOLEAN_TILE} is set to {@code true} for this |
| 143 | * tile |
| 144 | * @see TileService#META_DATA_BOOLEAN_TILE |
| 145 | */ |
| 146 | public boolean isBooleanTile() { |
| 147 | try { |
| 148 | ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(), |
| 149 | PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA); |
| 150 | return info.metaData != null |
| 151 | && info.metaData.getBoolean(TileService.META_DATA_BOOLEAN_TILE, false); |
| 152 | } catch (PackageManager.NameNotFoundException e) { |
| 153 | return false; |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | /** |
Jason Monk | 51c444b | 2016-01-06 16:32:29 -0500 | [diff] [blame] | 158 | * Binds just long enough to send any queued messages, then unbinds. |
| 159 | */ |
| 160 | public void flushMessagesAndUnbind() { |
| 161 | mUnbindImmediate = true; |
| 162 | setBindService(true); |
| 163 | } |
| 164 | |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 165 | public void setBindService(boolean bind) { |
Jason Monk | 34f6cbc | 2016-08-30 16:33:48 -0400 | [diff] [blame] | 166 | if (mBound && mUnbindImmediate) { |
| 167 | // If we are already bound and expecting to unbind, this means we should stay bound |
| 168 | // because something else wants to hold the connection open. |
| 169 | mUnbindImmediate = false; |
| 170 | return; |
| 171 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 172 | mBound = bind; |
| 173 | if (bind) { |
| 174 | if (mBindTryCount == MAX_BIND_RETRIES) { |
| 175 | // Too many failures, give up on this tile until an update. |
| 176 | startPackageListening(); |
| 177 | return; |
| 178 | } |
| 179 | if (!checkComponentState()) { |
| 180 | return; |
| 181 | } |
Jason Monk | 1ffa11b | 2016-03-08 14:44:23 -0500 | [diff] [blame] | 182 | if (DEBUG) Log.d(TAG, "Binding service " + mIntent + " " + mUser); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 183 | mBindTryCount++; |
Will Harmon | 604c2f9 | 2016-06-06 12:54:59 -0700 | [diff] [blame] | 184 | try { |
| 185 | mIsBound = mContext.bindServiceAsUser(mIntent, this, |
Fabian Kozynski | ff888da | 2019-07-01 12:50:03 -0400 | [diff] [blame] | 186 | Context.BIND_AUTO_CREATE |
| 187 | | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE |
| 188 | | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS |
| 189 | | Context.BIND_WAIVE_PRIORITY, |
| 190 | mUser); |
Will Harmon | 604c2f9 | 2016-06-06 12:54:59 -0700 | [diff] [blame] | 191 | } catch (SecurityException e) { |
| 192 | Log.e(TAG, "Failed to bind to service", e); |
| 193 | mIsBound = false; |
| 194 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 195 | } else { |
Jason Monk | 1ffa11b | 2016-03-08 14:44:23 -0500 | [diff] [blame] | 196 | if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent + " " + mUser); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 197 | // Give it another chance next time it needs to be bound, out of kindness. |
| 198 | mBindTryCount = 0; |
Jason Monk | fe8f682 | 2015-12-21 15:12:01 -0500 | [diff] [blame] | 199 | mWrapper = null; |
Jason Monk | 6d21e0d | 2016-05-25 11:37:47 -0400 | [diff] [blame] | 200 | if (mIsBound) { |
| 201 | mContext.unbindService(this); |
| 202 | mIsBound = false; |
| 203 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 204 | } |
| 205 | } |
| 206 | |
| 207 | @Override |
| 208 | public void onServiceConnected(ComponentName name, IBinder service) { |
| 209 | if (DEBUG) Log.d(TAG, "onServiceConnected " + name); |
| 210 | // Got a connection, set the binding count to 0. |
| 211 | mBindTryCount = 0; |
Jason Monk | 29c93ce | 2016-04-20 11:41:36 -0400 | [diff] [blame] | 212 | final QSTileServiceWrapper wrapper = new QSTileServiceWrapper(Stub.asInterface(service)); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 213 | try { |
| 214 | service.linkToDeath(this, 0); |
| 215 | } catch (RemoteException e) { |
| 216 | } |
Jason Monk | 29c93ce | 2016-04-20 11:41:36 -0400 | [diff] [blame] | 217 | mWrapper = wrapper; |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 218 | handlePendingMessages(); |
| 219 | } |
| 220 | |
| 221 | @Override |
| 222 | public void onServiceDisconnected(ComponentName name) { |
| 223 | if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name); |
Jason Monk | 624cbe2 | 2016-05-02 10:42:17 -0400 | [diff] [blame] | 224 | handleDeath(); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 225 | } |
| 226 | |
| 227 | private void handlePendingMessages() { |
| 228 | // This ordering is laid out manually to make sure we preserve the TileService |
| 229 | // lifecycle. |
| 230 | ArraySet<Integer> queue; |
| 231 | synchronized (mQueuedMessages) { |
| 232 | queue = new ArraySet<>(mQueuedMessages); |
| 233 | mQueuedMessages.clear(); |
| 234 | } |
| 235 | if (queue.contains(MSG_ON_ADDED)) { |
| 236 | if (DEBUG) Log.d(TAG, "Handling pending onAdded"); |
| 237 | onTileAdded(); |
| 238 | } |
| 239 | if (mListening) { |
| 240 | if (DEBUG) Log.d(TAG, "Handling pending onStartListening"); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 241 | onStartListening(); |
| 242 | } |
| 243 | if (queue.contains(MSG_ON_CLICK)) { |
| 244 | if (DEBUG) Log.d(TAG, "Handling pending onClick"); |
| 245 | if (!mListening) { |
| 246 | Log.w(TAG, "Managed to get click on non-listening state..."); |
| 247 | // Skipping click since lost click privileges. |
| 248 | } else { |
| 249 | onClick(mClickBinder); |
| 250 | } |
| 251 | } |
Jason Monk | 9429513 | 2016-01-12 11:27:02 -0500 | [diff] [blame] | 252 | if (queue.contains(MSG_ON_UNLOCK_COMPLETE)) { |
| 253 | if (DEBUG) Log.d(TAG, "Handling pending onUnlockComplete"); |
| 254 | if (!mListening) { |
| 255 | Log.w(TAG, "Managed to get unlock on non-listening state..."); |
| 256 | // Skipping unlock since lost click privileges. |
| 257 | } else { |
| 258 | onUnlockComplete(); |
| 259 | } |
| 260 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 261 | if (queue.contains(MSG_ON_REMOVED)) { |
| 262 | if (DEBUG) Log.d(TAG, "Handling pending onRemoved"); |
| 263 | if (mListening) { |
| 264 | Log.w(TAG, "Managed to get remove in listening state..."); |
| 265 | onStopListening(); |
| 266 | } |
| 267 | onTileRemoved(); |
| 268 | } |
Jason Monk | 51c444b | 2016-01-06 16:32:29 -0500 | [diff] [blame] | 269 | if (mUnbindImmediate) { |
| 270 | mUnbindImmediate = false; |
| 271 | setBindService(false); |
| 272 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 273 | } |
| 274 | |
| 275 | public void handleDestroy() { |
| 276 | if (DEBUG) Log.d(TAG, "handleDestroy"); |
| 277 | if (mReceiverRegistered) { |
| 278 | stopPackageListening(); |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | private void handleDeath() { |
| 283 | if (mWrapper == null) return; |
| 284 | mWrapper = null; |
| 285 | if (!mBound) return; |
| 286 | if (DEBUG) Log.d(TAG, "handleDeath"); |
| 287 | if (checkComponentState()) { |
| 288 | mHandler.postDelayed(new Runnable() { |
| 289 | @Override |
| 290 | public void run() { |
| 291 | if (mBound) { |
| 292 | // Retry binding. |
| 293 | setBindService(true); |
| 294 | } |
| 295 | } |
Geoffrey Pitsch | ebee1a3 | 2016-09-09 13:04:12 -0400 | [diff] [blame] | 296 | }, mBindRetryDelay); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 297 | } |
| 298 | } |
| 299 | |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 300 | private boolean checkComponentState() { |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 301 | if (!isPackageAvailable() || !isComponentAvailable()) { |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 302 | startPackageListening(); |
| 303 | return false; |
| 304 | } |
| 305 | return true; |
| 306 | } |
| 307 | |
| 308 | private void startPackageListening() { |
| 309 | if (DEBUG) Log.d(TAG, "startPackageListening"); |
| 310 | IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); |
| 311 | filter.addAction(Intent.ACTION_PACKAGE_CHANGED); |
| 312 | filter.addDataScheme("package"); |
| 313 | mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler); |
Jason Monk | 1c2fea8 | 2016-03-11 11:33:36 -0500 | [diff] [blame] | 314 | filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED); |
Fabian Kozynski | 5ca7a51 | 2019-10-16 19:56:11 +0000 | [diff] [blame] | 315 | mBroadcastDispatcher.registerReceiver(this, filter, mHandler, mUser); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 316 | mReceiverRegistered = true; |
| 317 | } |
| 318 | |
| 319 | private void stopPackageListening() { |
| 320 | if (DEBUG) Log.d(TAG, "stopPackageListening"); |
| 321 | mContext.unregisterReceiver(this); |
Fabian Kozynski | 5ca7a51 | 2019-10-16 19:56:11 +0000 | [diff] [blame] | 322 | mBroadcastDispatcher.unregisterReceiver(this); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 323 | mReceiverRegistered = false; |
| 324 | } |
| 325 | |
Jason Monk | 624cbe2 | 2016-05-02 10:42:17 -0400 | [diff] [blame] | 326 | public void setTileChangeListener(TileChangeListener changeListener) { |
| 327 | mChangeListener = changeListener; |
| 328 | } |
| 329 | |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 330 | @Override |
| 331 | public void onReceive(Context context, Intent intent) { |
| 332 | if (DEBUG) Log.d(TAG, "onReceive: " + intent); |
Jason Monk | 1c2fea8 | 2016-03-11 11:33:36 -0500 | [diff] [blame] | 333 | if (!Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { |
| 334 | Uri data = intent.getData(); |
| 335 | String pkgName = data.getEncodedSchemeSpecificPart(); |
Narayan Kamath | 607223f | 2018-02-19 14:09:02 +0000 | [diff] [blame] | 336 | if (!Objects.equals(pkgName, mIntent.getComponent().getPackageName())) { |
Jason Monk | 1c2fea8 | 2016-03-11 11:33:36 -0500 | [diff] [blame] | 337 | return; |
| 338 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 339 | } |
Jason Monk | 624cbe2 | 2016-05-02 10:42:17 -0400 | [diff] [blame] | 340 | if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) && mChangeListener != null) { |
| 341 | mChangeListener.onTileChanged(mIntent.getComponent()); |
| 342 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 343 | stopPackageListening(); |
| 344 | if (mBound) { |
| 345 | // Trying to bind again will check the state of the package before bothering to bind. |
| 346 | if (DEBUG) Log.d(TAG, "Trying to rebind"); |
| 347 | setBindService(true); |
| 348 | } |
| 349 | } |
| 350 | |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 351 | private boolean isComponentAvailable() { |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 352 | String packageName = mIntent.getComponent().getPackageName(); |
| 353 | try { |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 354 | ServiceInfo si = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(), |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 355 | 0, mUser.getIdentifier()); |
| 356 | if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent()); |
| 357 | return si != null; |
| 358 | } catch (RemoteException e) { |
| 359 | // Shouldn't happen. |
| 360 | } |
| 361 | return false; |
| 362 | } |
| 363 | |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 364 | private boolean isPackageAvailable() { |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 365 | String packageName = mIntent.getComponent().getPackageName(); |
| 366 | try { |
Geoffrey Pitsch | af2076a | 2016-08-31 12:44:08 -0400 | [diff] [blame] | 367 | mPackageManagerAdapter.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier()); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 368 | return true; |
| 369 | } catch (PackageManager.NameNotFoundException e) { |
| 370 | if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e); |
| 371 | else Log.d(TAG, "Package not available: " + packageName); |
| 372 | } |
| 373 | return false; |
| 374 | } |
| 375 | |
| 376 | private void queueMessage(int message) { |
| 377 | synchronized (mQueuedMessages) { |
| 378 | mQueuedMessages.add(message); |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | @Override |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 383 | public void onTileAdded() { |
| 384 | if (DEBUG) Log.d(TAG, "onTileAdded"); |
| 385 | if (mWrapper == null || !mWrapper.onTileAdded()) { |
| 386 | queueMessage(MSG_ON_ADDED); |
| 387 | handleDeath(); |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | @Override |
| 392 | public void onTileRemoved() { |
| 393 | if (DEBUG) Log.d(TAG, "onTileRemoved"); |
| 394 | if (mWrapper == null || !mWrapper.onTileRemoved()) { |
| 395 | queueMessage(MSG_ON_REMOVED); |
| 396 | handleDeath(); |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | @Override |
| 401 | public void onStartListening() { |
| 402 | if (DEBUG) Log.d(TAG, "onStartListening"); |
| 403 | mListening = true; |
| 404 | if (mWrapper != null && !mWrapper.onStartListening()) { |
| 405 | handleDeath(); |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | @Override |
| 410 | public void onStopListening() { |
| 411 | if (DEBUG) Log.d(TAG, "onStopListening"); |
| 412 | mListening = false; |
| 413 | if (mWrapper != null && !mWrapper.onStopListening()) { |
| 414 | handleDeath(); |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | @Override |
| 419 | public void onClick(IBinder iBinder) { |
Jason Monk | 1ffa11b | 2016-03-08 14:44:23 -0500 | [diff] [blame] | 420 | if (DEBUG) Log.d(TAG, "onClick " + iBinder + " " + mUser); |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 421 | if (mWrapper == null || !mWrapper.onClick(iBinder)) { |
| 422 | mClickBinder = iBinder; |
| 423 | queueMessage(MSG_ON_CLICK); |
| 424 | handleDeath(); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | @Override |
Jason Monk | 9429513 | 2016-01-12 11:27:02 -0500 | [diff] [blame] | 429 | public void onUnlockComplete() { |
| 430 | if (DEBUG) Log.d(TAG, "onUnlockComplete"); |
| 431 | if (mWrapper == null || !mWrapper.onUnlockComplete()) { |
| 432 | queueMessage(MSG_ON_UNLOCK_COMPLETE); |
| 433 | handleDeath(); |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | @Override |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 438 | public IBinder asBinder() { |
| 439 | return mWrapper != null ? mWrapper.asBinder() : null; |
| 440 | } |
| 441 | |
| 442 | @Override |
| 443 | public void binderDied() { |
| 444 | if (DEBUG) Log.d(TAG, "binderDeath"); |
| 445 | handleDeath(); |
| 446 | } |
Jason Monk | 624cbe2 | 2016-05-02 10:42:17 -0400 | [diff] [blame] | 447 | |
Jason Monk | ee68fd8 | 2016-06-23 13:12:23 -0400 | [diff] [blame] | 448 | public IBinder getToken() { |
| 449 | return mToken; |
| 450 | } |
| 451 | |
Jason Monk | 624cbe2 | 2016-05-02 10:42:17 -0400 | [diff] [blame] | 452 | public interface TileChangeListener { |
| 453 | void onTileChanged(ComponentName tile); |
| 454 | } |
Jason Monk | baade75 | 2016-08-25 15:57:14 -0400 | [diff] [blame] | 455 | |
| 456 | public static boolean isTileAdded(Context context, ComponentName component) { |
| 457 | return context.getSharedPreferences(TILES, 0).getBoolean(component.flattenToString(), false); |
| 458 | } |
| 459 | |
| 460 | public static void setTileAdded(Context context, ComponentName component, boolean added) { |
| 461 | context.getSharedPreferences(TILES, 0).edit().putBoolean(component.flattenToString(), |
| 462 | added).commit(); |
| 463 | } |
Jason Monk | d5a204f | 2015-12-21 08:50:01 -0500 | [diff] [blame] | 464 | } |