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