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 }