1 /* 2 * Copyright (C) 2016 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 17 package com.android.server.telecom; 18 19 import android.app.ActivityManager; 20 import android.content.BroadcastReceiver; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.res.Resources; 26 import android.database.ContentObserver; 27 import android.net.Uri; 28 import android.os.Handler; 29 import android.os.Looper; 30 import android.os.UserHandle; 31 import android.provider.Settings; 32 import android.telecom.DefaultDialerManager; 33 import android.telecom.Log; 34 import android.util.SparseArray; 35 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.internal.util.IndentingPrintWriter; 38 39 import java.util.Objects; 40 import java.util.concurrent.Executor; 41 import java.util.function.IntConsumer; 42 43 public class DefaultDialerCache { 44 public interface DefaultDialerManagerAdapter { getDefaultDialerApplication(Context context)45 String getDefaultDialerApplication(Context context); getDefaultDialerApplication(Context context, int userId)46 String getDefaultDialerApplication(Context context, int userId); setDefaultDialerApplication(Context context, String packageName, int userId)47 boolean setDefaultDialerApplication(Context context, String packageName, int userId); 48 } 49 50 static class DefaultDialerManagerAdapterImpl implements DefaultDialerManagerAdapter { 51 @Override getDefaultDialerApplication(Context context)52 public String getDefaultDialerApplication(Context context) { 53 return DefaultDialerManager.getDefaultDialerApplication(context); 54 } 55 56 @Override getDefaultDialerApplication(Context context, int userId)57 public String getDefaultDialerApplication(Context context, int userId) { 58 return DefaultDialerManager.getDefaultDialerApplication(context, userId); 59 } 60 61 @Override setDefaultDialerApplication(Context context, String packageName, int userId)62 public boolean setDefaultDialerApplication(Context context, String packageName, 63 int userId) { 64 return DefaultDialerManager.setDefaultDialerApplication(context, packageName, userId); 65 } 66 } 67 68 private static final String LOG_TAG = "DefaultDialerCache"; 69 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 70 @Override 71 public void onReceive(Context context, Intent intent) { 72 Log.startSession("DDC.oR"); 73 try { 74 String packageName; 75 if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) { 76 packageName = null; 77 } else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) 78 && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 79 packageName = intent.getData().getSchemeSpecificPart(); 80 } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { 81 packageName = null; 82 } else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { 83 packageName = null; 84 } else { 85 return; 86 } 87 88 synchronized (mLock) { 89 refreshCachesForUsersWithPackage(packageName); 90 } 91 92 } finally { 93 Log.endSession(); 94 } 95 } 96 }; 97 98 private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() { 99 @Override 100 public void onReceive(Context context, Intent intent) { 101 if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { 102 int removedUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 103 UserHandle.USER_NULL); 104 if (removedUser == UserHandle.USER_NULL) { 105 Log.w(LOG_TAG, "Expected EXTRA_USER_HANDLE with ACTION_USER_REMOVED"); 106 } else { 107 removeUserFromCache(removedUser); 108 Log.i(LOG_TAG, "Removing user %s", removedUser); 109 } 110 } 111 } 112 }; 113 114 private final Handler mHandler = new Handler(Looper.getMainLooper()); 115 private final ContentObserver mDefaultDialerObserver = new ContentObserver(mHandler) { 116 @Override 117 public void onChange(boolean selfChange) { 118 Log.startSession("DDC.oC"); 119 try { 120 // We don't get the user ID of the user that changed here, so we'll have to 121 // refresh all of the users. 122 synchronized (mLock) { 123 refreshCachesForUsersWithPackage(null); 124 } 125 } finally { 126 Log.endSession(); 127 } 128 } 129 130 @Override 131 public boolean deliverSelfNotifications() { 132 return true; 133 } 134 }; 135 136 private final Context mContext; 137 private final DefaultDialerManagerAdapter mDefaultDialerManagerAdapter; 138 private final TelecomSystem.SyncRoot mLock; 139 private final ComponentName mSystemDialerComponentName; 140 private final RoleManagerAdapter mRoleManagerAdapter; 141 private SparseArray<String> mCurrentDefaultDialerPerUser = new SparseArray<>(); 142 private ComponentName mOverrideSystemDialerComponentName; 143 DefaultDialerCache(Context context, DefaultDialerManagerAdapter defaultDialerManagerAdapter, RoleManagerAdapter roleManagerAdapter, TelecomSystem.SyncRoot lock)144 public DefaultDialerCache(Context context, 145 DefaultDialerManagerAdapter defaultDialerManagerAdapter, 146 RoleManagerAdapter roleManagerAdapter, 147 TelecomSystem.SyncRoot lock) { 148 mContext = context; 149 mDefaultDialerManagerAdapter = defaultDialerManagerAdapter; 150 mRoleManagerAdapter = roleManagerAdapter; 151 mLock = lock; 152 Resources resources = mContext.getResources(); 153 mSystemDialerComponentName = new ComponentName(resources.getString( 154 com.android.internal.R.string.config_defaultDialer), 155 resources.getString(R.string.incall_default_class)); 156 157 158 IntentFilter packageIntentFilter = new IntentFilter(); 159 packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 160 packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 161 packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 162 packageIntentFilter.addDataScheme("package"); 163 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, packageIntentFilter, null, null); 164 165 IntentFilter bootIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 166 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, bootIntentFilter, null, null); 167 168 IntentFilter userRemovedFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); 169 context.registerReceiver(mUserRemovedReceiver, userRemovedFilter); 170 171 Uri defaultDialerSetting = 172 Settings.Secure.getUriFor(Settings.Secure.DIALER_DEFAULT_APPLICATION); 173 context.getContentResolver() 174 .registerContentObserver(defaultDialerSetting, false, mDefaultDialerObserver, 175 UserHandle.USER_ALL); 176 } 177 getDefaultDialerApplication(int userId)178 public String getDefaultDialerApplication(int userId) { 179 if (userId == UserHandle.USER_CURRENT) { 180 userId = ActivityManager.getCurrentUser(); 181 } 182 183 if (userId < 0) { 184 Log.w(LOG_TAG, "Attempting to get default dialer for a meta-user %d", userId); 185 return null; 186 } 187 188 // TODO: Re-enable this when we are able to use the cache once more. RoleManager does not 189 // provide a means for being informed when the role holder changes at the current time. 190 // 191 //synchronized (mLock) { 192 // String defaultDialer = mCurrentDefaultDialerPerUser.get(userId); 193 // if (defaultDialer != null) { 194 // return defaultDialer; 195 // } 196 //} 197 return refreshCacheForUser(userId); 198 } 199 getDefaultDialerApplication()200 public String getDefaultDialerApplication() { 201 return getDefaultDialerApplication(mContext.getUserId()); 202 } 203 setSystemDialerComponentName(ComponentName testComponentName)204 public void setSystemDialerComponentName(ComponentName testComponentName) { 205 mOverrideSystemDialerComponentName = testComponentName; 206 } 207 getSystemDialerApplication()208 public String getSystemDialerApplication() { 209 if (mOverrideSystemDialerComponentName != null) { 210 return mOverrideSystemDialerComponentName.getPackageName(); 211 } 212 return mSystemDialerComponentName.getPackageName(); 213 } 214 getSystemDialerComponent()215 public ComponentName getSystemDialerComponent() { 216 if (mOverrideSystemDialerComponentName != null) return mOverrideSystemDialerComponentName; 217 return mSystemDialerComponentName; 218 } 219 getDialtactsSystemDialerComponent()220 public ComponentName getDialtactsSystemDialerComponent() { 221 final Resources resources = mContext.getResources(); 222 return new ComponentName(getSystemDialerApplication(), 223 resources.getString(R.string.dialer_default_class)); 224 } 225 observeDefaultDialerApplication(Executor executor, IntConsumer observer)226 public void observeDefaultDialerApplication(Executor executor, IntConsumer observer) { 227 mRoleManagerAdapter.observeDefaultDialerApp(executor, observer); 228 } 229 isDefaultOrSystemDialer(String packageName, int userId)230 public boolean isDefaultOrSystemDialer(String packageName, int userId) { 231 String defaultDialer = getDefaultDialerApplication(userId); 232 return Objects.equals(packageName, defaultDialer) 233 || Objects.equals(packageName, getSystemDialerApplication()); 234 } 235 setDefaultDialer(String packageName, int userId)236 public boolean setDefaultDialer(String packageName, int userId) { 237 boolean isChanged = mDefaultDialerManagerAdapter.setDefaultDialerApplication( 238 mContext, packageName, userId); 239 if(isChanged) { 240 synchronized (mLock) { 241 // Update the cache synchronously so that there is no delay in cache update. 242 mCurrentDefaultDialerPerUser.put(userId, packageName); 243 } 244 } 245 return isChanged; 246 } 247 refreshCacheForUser(int userId)248 private String refreshCacheForUser(int userId) { 249 String currentDefaultDialer = 250 mRoleManagerAdapter.getDefaultDialerApp(userId); 251 synchronized (mLock) { 252 mCurrentDefaultDialerPerUser.put(userId, currentDefaultDialer); 253 } 254 return currentDefaultDialer; 255 } 256 257 /** 258 * Refreshes the cache for users that currently have packageName as their cached default dialer. 259 * If packageName is null, refresh all caches. 260 * @param packageName Name of the affected package. 261 */ refreshCachesForUsersWithPackage(String packageName)262 private void refreshCachesForUsersWithPackage(String packageName) { 263 for (int i = 0; i < mCurrentDefaultDialerPerUser.size(); i++) { 264 int userId = mCurrentDefaultDialerPerUser.keyAt(i); 265 if (packageName == null || 266 Objects.equals(packageName, mCurrentDefaultDialerPerUser.get(userId))) { 267 String newDefaultDialer = refreshCacheForUser(userId); 268 Log.i(LOG_TAG, "Refreshing default dialer for user %d: now %s", 269 userId, newDefaultDialer); 270 } 271 } 272 } 273 dumpCache(IndentingPrintWriter pw)274 public void dumpCache(IndentingPrintWriter pw) { 275 synchronized (mLock) { 276 for (int i = 0; i < mCurrentDefaultDialerPerUser.size(); i++) { 277 pw.printf("User %d: %s\n", mCurrentDefaultDialerPerUser.keyAt(i), 278 mCurrentDefaultDialerPerUser.valueAt(i)); 279 } 280 } 281 } 282 removeUserFromCache(int userId)283 private void removeUserFromCache(int userId) { 284 synchronized (mLock) { 285 mCurrentDefaultDialerPerUser.remove(userId); 286 } 287 } 288 289 /** 290 * registerContentObserver is really hard to mock out, so here is a getter method for the 291 * content observer for testing instead. 292 * @return The content observer 293 */ 294 @VisibleForTesting getContentObserver()295 public ContentObserver getContentObserver() { 296 return mDefaultDialerObserver; 297 } 298 getRoleManagerAdapter()299 public RoleManagerAdapter getRoleManagerAdapter() { 300 return mRoleManagerAdapter; 301 } 302 }