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