Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2011 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.inputmethod.latin;
     18 
     19 import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
     20 import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
     21 
     22 import android.content.BroadcastReceiver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.pm.PackageInfo;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.ProviderInfo;
     28 import android.net.Uri;
     29 import android.util.Log;
     30 
     31 /**
     32  * Receives broadcasts pertaining to dictionary management and takes the appropriate action.
     33  *
     34  * This object receives three types of broadcasts.
     35  * - Package installed/added. When a dictionary provider application is added or removed, we
     36  * need to query the dictionaries.
     37  * - New dictionary broadcast. The dictionary provider broadcasts new dictionary availability. When
     38  * this happens, we need to re-query the dictionaries.
     39  * - Unknown client. If the dictionary provider is in urgent need of data about some client that
     40  * it does not know, it sends this broadcast. When we receive this, we need to tell the dictionary
     41  * provider about ourselves. This happens when the settings for the dictionary pack are accessed,
     42  * but Latin IME never got a chance to register itself.
     43  */
     44 public final class DictionaryPackInstallBroadcastReceiver extends BroadcastReceiver {
     45     private static final String TAG = DictionaryPackInstallBroadcastReceiver.class.getSimpleName();
     46 
     47     final LatinIME mService;
     48 
     49     public DictionaryPackInstallBroadcastReceiver() {
     50         // This empty constructor is necessary for the system to instantiate this receiver.
     51         // This happens when the dictionary pack says it can't find a record for our client,
     52         // which happens when the dictionary pack settings are called before the keyboard
     53         // was ever started once.
     54         Log.i(TAG, "Latin IME dictionary broadcast receiver instantiated from the framework.");
     55         mService = null;
     56     }
     57 
     58     public DictionaryPackInstallBroadcastReceiver(final LatinIME service) {
     59         mService = service;
     60     }
     61 
     62     @Override
     63     public void onReceive(Context context, Intent intent) {
     64         final String action = intent.getAction();
     65         final PackageManager manager = context.getPackageManager();
     66 
     67         // We need to reread the dictionary if a new dictionary package is installed.
     68         if (action.equals(Intent.ACTION_PACKAGE_ADDED)) {
     69             if (null == mService) {
     70                 Log.e(TAG, "Called with intent " + action + " but we don't know the service: this "
     71                         + "should never happen");
     72                 return;
     73             }
     74             final Uri packageUri = intent.getData();
     75             if (null == packageUri) return; // No package name : we can't do anything
     76             final String packageName = packageUri.getSchemeSpecificPart();
     77             if (null == packageName) return;
     78             // TODO: do this in a more appropriate place
     79             TargetPackageInfoGetterTask.removeCachedPackageInfo(packageName);
     80             final PackageInfo packageInfo;
     81             try {
     82                 packageInfo = manager.getPackageInfo(packageName, PackageManager.GET_PROVIDERS);
     83             } catch (android.content.pm.PackageManager.NameNotFoundException e) {
     84                 return; // No package info : we can't do anything
     85             }
     86             final ProviderInfo[] providers = packageInfo.providers;
     87             if (null == providers) return; // No providers : it is not a dictionary.
     88 
     89             // Search for some dictionary pack in the just-installed package. If found, reread.
     90             for (ProviderInfo info : providers) {
     91                 if (DictionaryPackConstants.AUTHORITY.equals(info.authority)) {
     92                     mService.resetSuggestMainDict();
     93                     return;
     94                 }
     95             }
     96             // If we come here none of the authorities matched the one we searched for.
     97             // We can exit safely.
     98             return;
     99         } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
    100                 && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
    101             if (null == mService) {
    102                 Log.e(TAG, "Called with intent " + action + " but we don't know the service: this "
    103                         + "should never happen");
    104                 return;
    105             }
    106             // When the dictionary package is removed, we need to reread dictionary (to use the
    107             // next-priority one, or stop using a dictionary at all if this was the only one,
    108             // since this is the user request).
    109             // If we are replacing the package, we will receive ADDED right away so no need to
    110             // remove the dictionary at the moment, since we will do it when we receive the
    111             // ADDED broadcast.
    112 
    113             // TODO: Only reload dictionary on REMOVED when the removed package is the one we
    114             // read dictionary from?
    115             mService.resetSuggestMainDict();
    116         } else if (action.equals(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION)) {
    117             if (null == mService) {
    118                 Log.e(TAG, "Called with intent " + action + " but we don't know the service: this "
    119                         + "should never happen");
    120                 return;
    121             }
    122             mService.resetSuggestMainDict();
    123         } else if (action.equals(DictionaryPackConstants.UNKNOWN_DICTIONARY_PROVIDER_CLIENT)) {
    124             if (null != mService) {
    125                 // Careful! This is returning if the service is NOT null. This is because we
    126                 // should come here instantiated by the framework in reaction to a broadcast of
    127                 // the above action, so we should gave gone through the no-args constructor.
    128                 Log.e(TAG, "Called with intent " + action + " but we have a reference to the "
    129                         + "service: this should never happen");
    130                 return;
    131             }
    132             // The dictionary provider does not know about some client. We check that it's really
    133             // us that it needs to know about, and if it's the case, we register with the provider.
    134             final String wantedClientId =
    135                     intent.getStringExtra(DictionaryPackConstants.DICTIONARY_PROVIDER_CLIENT_EXTRA);
    136             final String myClientId = context.getString(R.string.dictionary_pack_client_id);
    137             if (!wantedClientId.equals(myClientId)) return; // Not for us
    138             BinaryDictionaryFileDumper.initializeClientRecordHelper(context, myClientId);
    139         }
    140     }
    141 }
    142