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