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 packageIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 164 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, packageIntentFilter, null, null); 165 166 IntentFilter bootIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 167 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, bootIntentFilter, null, null); 168 169 IntentFilter userRemovedFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); 170 context.registerReceiver(mUserRemovedReceiver, userRemovedFilter); 171 172 Uri defaultDialerSetting = 173 Settings.Secure.getUriFor(Settings.Secure.DIALER_DEFAULT_APPLICATION); 174 context.getContentResolver() 175 .registerContentObserver(defaultDialerSetting, false, mDefaultDialerObserver, 176 UserHandle.USER_ALL); 177 } 178 getDefaultDialerApplication(int userId)179 public String getDefaultDialerApplication(int userId) { 180 if (userId == UserHandle.USER_CURRENT) { 181 userId = ActivityManager.getCurrentUser(); 182 } 183 184 if (userId < 0) { 185 Log.w(LOG_TAG, "Attempting to get default dialer for a meta-user %d", userId); 186 return null; 187 } 188 189 // TODO: Re-enable this when we are able to use the cache once more. RoleManager does not 190 // provide a means for being informed when the role holder changes at the current time. 191 // 192 //synchronized (mLock) { 193 // String defaultDialer = mCurrentDefaultDialerPerUser.get(userId); 194 // if (defaultDialer != null) { 195 // return defaultDialer; 196 // } 197 //} 198 return refreshCacheForUser(userId); 199 } 200 getDefaultDialerApplication()201 public String getDefaultDialerApplication() { 202 return getDefaultDialerApplication(mContext.getUserId()); 203 } 204 setSystemDialerComponentName(ComponentName testComponentName)205 public void setSystemDialerComponentName(ComponentName testComponentName) { 206 mOverrideSystemDialerComponentName = testComponentName; 207 } 208 getSystemDialerApplication()209 public String getSystemDialerApplication() { 210 if (mOverrideSystemDialerComponentName != null) { 211 return mOverrideSystemDialerComponentName.getPackageName(); 212 } 213 return mSystemDialerComponentName.getPackageName(); 214 } 215 getSystemDialerComponent()216 public ComponentName getSystemDialerComponent() { 217 if (mOverrideSystemDialerComponentName != null) return mOverrideSystemDialerComponentName; 218 return mSystemDialerComponentName; 219 } 220 getDialtactsSystemDialerComponent()221 public ComponentName getDialtactsSystemDialerComponent() { 222 final Resources resources = mContext.getResources(); 223 return new ComponentName(getSystemDialerApplication(), 224 resources.getString(R.string.dialer_default_class)); 225 } 226 observeDefaultDialerApplication(Executor executor, IntConsumer observer)227 public void observeDefaultDialerApplication(Executor executor, IntConsumer observer) { 228 mRoleManagerAdapter.observeDefaultDialerApp(executor, observer); 229 } 230 isDefaultOrSystemDialer(String packageName, int userId)231 public boolean isDefaultOrSystemDialer(String packageName, int userId) { 232 String defaultDialer = getDefaultDialerApplication(userId); 233 return Objects.equals(packageName, defaultDialer) 234 || Objects.equals(packageName, getSystemDialerApplication()); 235 } 236 setDefaultDialer(String packageName, int userId)237 public boolean setDefaultDialer(String packageName, int userId) { 238 boolean isChanged = mDefaultDialerManagerAdapter.setDefaultDialerApplication( 239 mContext, packageName, userId); 240 if(isChanged) { 241 synchronized (mLock) { 242 // Update the cache synchronously so that there is no delay in cache update. 243 mCurrentDefaultDialerPerUser.put(userId, packageName); 244 } 245 } 246 return isChanged; 247 } 248 refreshCacheForUser(int userId)249 private String refreshCacheForUser(int userId) { 250 String currentDefaultDialer = 251 mRoleManagerAdapter.getDefaultDialerApp(userId); 252 synchronized (mLock) { 253 mCurrentDefaultDialerPerUser.put(userId, currentDefaultDialer); 254 } 255 return currentDefaultDialer; 256 } 257 258 /** 259 * Refreshes the cache for users that currently have packageName as their cached default dialer. 260 * If packageName is null, refresh all caches. 261 * @param packageName Name of the affected package. 262 */ refreshCachesForUsersWithPackage(String packageName)263 private void refreshCachesForUsersWithPackage(String packageName) { 264 for (int i = 0; i < mCurrentDefaultDialerPerUser.size(); i++) { 265 int userId = mCurrentDefaultDialerPerUser.keyAt(i); 266 if (packageName == null || 267 Objects.equals(packageName, mCurrentDefaultDialerPerUser.get(userId))) { 268 String newDefaultDialer = refreshCacheForUser(userId); 269 Log.v(LOG_TAG, "Refreshing default dialer for user %d: now %s", 270 userId, newDefaultDialer); 271 } 272 } 273 } 274 dumpCache(IndentingPrintWriter pw)275 public void dumpCache(IndentingPrintWriter pw) { 276 synchronized (mLock) { 277 for (int i = 0; i < mCurrentDefaultDialerPerUser.size(); i++) { 278 pw.printf("User %d: %s\n", mCurrentDefaultDialerPerUser.keyAt(i), 279 mCurrentDefaultDialerPerUser.valueAt(i)); 280 } 281 } 282 } 283 removeUserFromCache(int userId)284 private void removeUserFromCache(int userId) { 285 synchronized (mLock) { 286 mCurrentDefaultDialerPerUser.remove(userId); 287 } 288 } 289 290 /** 291 * registerContentObserver is really hard to mock out, so here is a getter method for the 292 * content observer for testing instead. 293 * @return The content observer 294 */ 295 @VisibleForTesting getContentObserver()296 public ContentObserver getContentObserver() { 297 return mDefaultDialerObserver; 298 } 299 getRoleManagerAdapter()300 public RoleManagerAdapter getRoleManagerAdapter() { 301 return mRoleManagerAdapter; 302 } 303 }