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