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