blob: 09ef71024ad4e6e88f9cb7c1cbd5e8623a639bcb [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
17package android.app;
18
svetoslavganov75986cf2009-05-14 22:28:01 -070019import com.android.internal.policy.PolicyManager;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080020import com.android.internal.util.XmlUtils;
svetoslavganov75986cf2009-05-14 22:28:01 -070021import com.google.android.collect.Maps;
22
23import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.BroadcastReceiver;
26import android.content.ComponentName;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.ContextWrapper;
30import android.content.IContentProvider;
31import android.content.Intent;
32import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070033import android.content.IIntentReceiver;
34import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.content.ReceiverCallNotAllowedException;
36import android.content.ServiceConnection;
37import android.content.SharedPreferences;
38import android.content.pm.ActivityInfo;
39import android.content.pm.ApplicationInfo;
40import android.content.pm.ComponentInfo;
Dianne Hackborn49237342009-08-27 20:08:01 -070041import android.content.pm.FeatureInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.content.pm.IPackageDataObserver;
43import android.content.pm.IPackageDeleteObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.content.pm.IPackageInstallObserver;
Suchi Amalapurapu8946dd32010-02-19 09:19:34 -080045import android.content.pm.IPackageMoveObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.pm.IPackageManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070047import android.content.pm.IPackageStatsObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.pm.InstrumentationInfo;
49import android.content.pm.PackageInfo;
50import android.content.pm.PackageManager;
51import android.content.pm.PermissionGroupInfo;
52import android.content.pm.PermissionInfo;
53import android.content.pm.ProviderInfo;
54import android.content.pm.ResolveInfo;
55import android.content.pm.ServiceInfo;
Suchi Amalapurapu117818e2010-02-09 03:45:40 -080056import android.content.pm.PackageParser.Package;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.content.res.AssetManager;
58import android.content.res.Resources;
59import android.content.res.XmlResourceParser;
60import android.database.sqlite.SQLiteDatabase;
61import android.database.sqlite.SQLiteDatabase.CursorFactory;
62import android.graphics.Bitmap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.graphics.drawable.Drawable;
64import android.hardware.SensorManager;
65import android.location.ILocationManager;
66import android.location.LocationManager;
67import android.media.AudioManager;
68import android.net.ConnectivityManager;
69import android.net.IConnectivityManager;
Steve Howarda2709362010-07-02 17:12:48 -070070import android.net.DownloadManager;
Irfan Sheriffc9b68512010-04-08 14:12:33 -070071import android.net.ThrottleManager;
72import android.net.IThrottleManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.net.Uri;
74import android.net.wifi.IWifiManager;
75import android.net.wifi.WifiManager;
76import android.os.Binder;
77import android.os.Bundle;
Dan Egnorf18a01c2009-11-12 11:32:50 -080078import android.os.DropBoxManager;
Oscar Montemayor539d3c42010-01-29 15:27:00 -080079import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.FileUtils;
81import android.os.Handler;
82import android.os.IBinder;
83import android.os.IPowerManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070084import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.PowerManager;
86import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070087import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.os.ServiceManager;
Oscar Montemayor539d3c42010-01-29 15:27:00 -080089import android.os.StatFs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.os.Vibrator;
91import android.os.FileUtils.FileStatus;
San Mehatb1043402010-02-05 08:26:50 -080092import android.os.storage.StorageManager;
Suchi Amalapurapu117818e2010-02-09 03:45:40 -080093import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.telephony.TelephonyManager;
95import android.text.ClipboardManager;
96import android.util.AndroidRuntimeException;
97import android.util.Log;
98import android.view.ContextThemeWrapper;
99import android.view.LayoutInflater;
100import android.view.WindowManagerImpl;
svetoslavganov75986cf2009-05-14 22:28:01 -0700101import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import android.view.inputmethod.InputMethodManager;
Fred Quintana60307342009-03-24 22:48:12 -0700103import android.accounts.AccountManager;
104import android.accounts.IAccountManager;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800105import android.app.admin.DevicePolicyManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Dan Egnorf18a01c2009-11-12 11:32:50 -0800107import com.android.internal.os.IDropBoxManagerService;
Dan Egnor95240272009-10-27 18:23:39 -0700108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.File;
110import java.io.FileInputStream;
111import java.io.FileNotFoundException;
112import java.io.FileOutputStream;
113import java.io.IOException;
114import java.io.InputStream;
115import java.lang.ref.WeakReference;
116import java.util.ArrayList;
117import java.util.HashMap;
svetoslavganov75986cf2009-05-14 22:28:01 -0700118import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import java.util.Iterator;
120import java.util.List;
121import java.util.Map;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700122import java.util.Map.Entry;
The Android Open Source Project10592532009-03-18 17:39:46 -0700123import java.util.Set;
svetoslavganov75986cf2009-05-14 22:28:01 -0700124import java.util.WeakHashMap;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700125import java.util.concurrent.CountDownLatch;
126import java.util.concurrent.ExecutorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128class ReceiverRestrictedContext extends ContextWrapper {
129 ReceiverRestrictedContext(Context base) {
130 super(base);
131 }
132
133 @Override
134 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
135 return registerReceiver(receiver, filter, null, null);
136 }
137
138 @Override
139 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
140 String broadcastPermission, Handler scheduler) {
141 throw new ReceiverCallNotAllowedException(
142 "IntentReceiver components are not allowed to register to receive intents");
143 //ex.fillInStackTrace();
144 //Log.e("IntentReceiver", ex.getMessage(), ex);
145 //return mContext.registerReceiver(receiver, filter, broadcastPermission,
146 // scheduler);
147 }
148
149 @Override
150 public boolean bindService(Intent service, ServiceConnection conn, int flags) {
151 throw new ReceiverCallNotAllowedException(
152 "IntentReceiver components are not allowed to bind to services");
153 //ex.fillInStackTrace();
154 //Log.e("IntentReceiver", ex.getMessage(), ex);
155 //return mContext.bindService(service, interfaceName, conn, flags);
156 }
157}
158
159/**
Dianne Hackborn21556372010-02-04 16:34:40 -0800160 * Common implementation of Context API, which provides the base
161 * context object for Activity and other application components.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 */
Dianne Hackborn21556372010-02-04 16:34:40 -0800163class ContextImpl extends Context {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 private final static String TAG = "ApplicationContext";
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700165 private final static boolean DEBUG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 private final static boolean DEBUG_ICONS = false;
167
168 private static final Object sSync = new Object();
169 private static AlarmManager sAlarmManager;
170 private static PowerManager sPowerManager;
171 private static ConnectivityManager sConnectivityManager;
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700172 private static ThrottleManager sThrottleManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 private static WifiManager sWifiManager;
174 private static LocationManager sLocationManager;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700175 private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
176 new HashMap<String, SharedPreferencesImpl>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
178 private AudioManager mAudioManager;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700179 /*package*/ LoadedApk mPackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 private Resources mResources;
181 /*package*/ ActivityThread mMainThread;
182 private Context mOuterContext;
183 private IBinder mActivityToken = null;
184 private ApplicationContentResolver mContentResolver;
185 private int mThemeResource = 0;
186 private Resources.Theme mTheme = null;
187 private PackageManager mPackageManager;
188 private NotificationManager mNotificationManager = null;
189 private ActivityManager mActivityManager = null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700190 private WallpaperManager mWallpaperManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 private Context mReceiverRestrictedContext = null;
192 private SearchManager mSearchManager = null;
193 private SensorManager mSensorManager = null;
San Mehatc9d81752010-02-01 10:23:27 -0800194 private StorageManager mStorageManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private Vibrator mVibrator = null;
196 private LayoutInflater mLayoutInflater = null;
197 private StatusBarManager mStatusBarManager = null;
198 private TelephonyManager mTelephonyManager = null;
199 private ClipboardManager mClipboardManager = null;
Romain Guy870e09f2009-07-06 16:35:25 -0700200 private boolean mRestricted;
Fred Quintanae00a3112009-09-22 15:13:30 -0700201 private AccountManager mAccountManager; // protected by mSync
Dan Egnorf18a01c2009-11-12 11:32:50 -0800202 private DropBoxManager mDropBoxManager = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800203 private DevicePolicyManager mDevicePolicyManager = null;
Tobias Haamel53332882010-02-18 16:15:43 -0800204 private UiModeManager mUiModeManager = null;
Steve Howarda2709362010-07-02 17:12:48 -0700205 private DownloadManager mDownloadManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
207 private final Object mSync = new Object();
208
209 private File mDatabasesDir;
210 private File mPreferencesDir;
211 private File mFilesDir;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 private File mCacheDir;
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800213 private File mExternalFilesDir;
214 private File mExternalCacheDir;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 private static long sInstanceCount = 0;
217
218 private static final String[] EMPTY_FILE_LIST = {};
219
Carl Shapiro82fe5642010-02-24 00:14:23 -0800220 // For debug only
221 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 @Override
223 protected void finalize() throws Throwable {
224 super.finalize();
225 --sInstanceCount;
226 }
Carl Shapiro82fe5642010-02-24 00:14:23 -0800227 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228
229 public static long getInstanceCount() {
230 return sInstanceCount;
231 }
232
233 @Override
234 public AssetManager getAssets() {
235 return mResources.getAssets();
236 }
237
238 @Override
239 public Resources getResources() {
240 return mResources;
241 }
242
243 @Override
244 public PackageManager getPackageManager() {
245 if (mPackageManager != null) {
246 return mPackageManager;
247 }
248
249 IPackageManager pm = ActivityThread.getPackageManager();
250 if (pm != null) {
251 // Doesn't matter if we make more than one instance.
252 return (mPackageManager = new ApplicationPackageManager(this, pm));
253 }
254
255 return null;
256 }
257
258 @Override
259 public ContentResolver getContentResolver() {
260 return mContentResolver;
261 }
262
263 @Override
264 public Looper getMainLooper() {
265 return mMainThread.getLooper();
266 }
267
268 @Override
269 public Context getApplicationContext() {
Christopher Tateeb9e9ec2010-03-23 17:14:36 -0700270 return (mPackageInfo != null) ?
271 mPackageInfo.getApplication() : mMainThread.getApplication();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 }
273
274 @Override
275 public void setTheme(int resid) {
276 mThemeResource = resid;
277 }
278
279 @Override
280 public Resources.Theme getTheme() {
281 if (mTheme == null) {
282 if (mThemeResource == 0) {
283 mThemeResource = com.android.internal.R.style.Theme;
284 }
285 mTheme = mResources.newTheme();
286 mTheme.applyStyle(mThemeResource, true);
287 }
288 return mTheme;
289 }
290
291 @Override
292 public ClassLoader getClassLoader() {
293 return mPackageInfo != null ?
294 mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
295 }
296
297 @Override
298 public String getPackageName() {
299 if (mPackageInfo != null) {
300 return mPackageInfo.getPackageName();
301 }
302 throw new RuntimeException("Not supported in system context");
303 }
304
305 @Override
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700306 public ApplicationInfo getApplicationInfo() {
307 if (mPackageInfo != null) {
308 return mPackageInfo.getApplicationInfo();
309 }
310 throw new RuntimeException("Not supported in system context");
311 }
312
313 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 public String getPackageResourcePath() {
315 if (mPackageInfo != null) {
316 return mPackageInfo.getResDir();
317 }
318 throw new RuntimeException("Not supported in system context");
319 }
320
321 @Override
322 public String getPackageCodePath() {
323 if (mPackageInfo != null) {
324 return mPackageInfo.getAppDir();
325 }
326 throw new RuntimeException("Not supported in system context");
327 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 private static File makeBackupFile(File prefsFile) {
330 return new File(prefsFile.getPath() + ".bak");
331 }
332
Joe Onorato23ecae32009-06-10 17:07:15 -0700333 public File getSharedPrefsFile(String name) {
334 return makeFilename(getPreferencesDir(), name + ".xml");
335 }
336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 @Override
338 public SharedPreferences getSharedPreferences(String name, int mode) {
339 SharedPreferencesImpl sp;
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700340 File prefsFile;
341 boolean needInitialLoad = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 synchronized (sSharedPrefs) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700343 sp = sSharedPrefs.get(name);
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700344 if (sp != null && !sp.hasFileChangedUnexpectedly()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 return sp;
346 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700347 prefsFile = getSharedPrefsFile(name);
348 if (sp == null) {
349 sp = new SharedPreferencesImpl(prefsFile, mode, null);
350 sSharedPrefs.put(name, sp);
351 needInitialLoad = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 }
353 }
354
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700355 synchronized (sp) {
356 if (needInitialLoad && sp.isLoaded()) {
357 // lost the race to load; another thread handled it
358 return sp;
359 }
360 File backup = makeBackupFile(prefsFile);
361 if (backup.exists()) {
362 prefsFile.delete();
363 backup.renameTo(prefsFile);
364 }
365
366 // Debugging
367 if (prefsFile.exists() && !prefsFile.canRead()) {
368 Log.w(TAG, "Attempt to read preferences file " + prefsFile + " without permission");
369 }
370
371 Map map = null;
372 if (prefsFile.exists() && prefsFile.canRead()) {
373 try {
374 FileInputStream str = new FileInputStream(prefsFile);
375 map = XmlUtils.readMapXml(str);
376 str.close();
377 } catch (org.xmlpull.v1.XmlPullParserException e) {
378 Log.w(TAG, "getSharedPreferences", e);
379 } catch (FileNotFoundException e) {
380 Log.w(TAG, "getSharedPreferences", e);
381 } catch (IOException e) {
382 Log.w(TAG, "getSharedPreferences", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 }
384 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700385 sp.replace(map);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700387 return sp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 }
389
390 private File getPreferencesDir() {
391 synchronized (mSync) {
392 if (mPreferencesDir == null) {
393 mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
394 }
395 return mPreferencesDir;
396 }
397 }
398
399 @Override
400 public FileInputStream openFileInput(String name)
401 throws FileNotFoundException {
402 File f = makeFilename(getFilesDir(), name);
403 return new FileInputStream(f);
404 }
405
406 @Override
407 public FileOutputStream openFileOutput(String name, int mode)
408 throws FileNotFoundException {
409 final boolean append = (mode&MODE_APPEND) != 0;
410 File f = makeFilename(getFilesDir(), name);
411 try {
412 FileOutputStream fos = new FileOutputStream(f, append);
413 setFilePermissionsFromMode(f.getPath(), mode, 0);
414 return fos;
415 } catch (FileNotFoundException e) {
416 }
417
418 File parent = f.getParentFile();
419 parent.mkdir();
420 FileUtils.setPermissions(
421 parent.getPath(),
422 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
423 -1, -1);
424 FileOutputStream fos = new FileOutputStream(f, append);
425 setFilePermissionsFromMode(f.getPath(), mode, 0);
426 return fos;
427 }
428
429 @Override
430 public boolean deleteFile(String name) {
431 File f = makeFilename(getFilesDir(), name);
432 return f.delete();
433 }
434
435 @Override
436 public File getFilesDir() {
437 synchronized (mSync) {
438 if (mFilesDir == null) {
439 mFilesDir = new File(getDataDirFile(), "files");
440 }
441 if (!mFilesDir.exists()) {
442 if(!mFilesDir.mkdirs()) {
443 Log.w(TAG, "Unable to create files directory");
444 return null;
445 }
446 FileUtils.setPermissions(
447 mFilesDir.getPath(),
448 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
449 -1, -1);
450 }
451 return mFilesDir;
452 }
453 }
454
455 @Override
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800456 public File getExternalFilesDir(String type) {
457 synchronized (mSync) {
458 if (mExternalFilesDir == null) {
459 mExternalFilesDir = Environment.getExternalStorageAppFilesDirectory(
460 getPackageName());
461 }
462 if (!mExternalFilesDir.exists()) {
463 try {
464 (new File(Environment.getExternalStorageAndroidDataDir(),
465 ".nomedia")).createNewFile();
466 } catch (IOException e) {
467 }
468 if (!mExternalFilesDir.mkdirs()) {
469 Log.w(TAG, "Unable to create external files directory");
470 return null;
471 }
472 }
473 if (type == null) {
474 return mExternalFilesDir;
475 }
476 File dir = new File(mExternalFilesDir, type);
477 if (!dir.exists()) {
478 if (!dir.mkdirs()) {
479 Log.w(TAG, "Unable to create external media directory " + dir);
480 return null;
481 }
482 }
483 return dir;
484 }
485 }
486
487 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 public File getCacheDir() {
489 synchronized (mSync) {
490 if (mCacheDir == null) {
491 mCacheDir = new File(getDataDirFile(), "cache");
492 }
493 if (!mCacheDir.exists()) {
494 if(!mCacheDir.mkdirs()) {
495 Log.w(TAG, "Unable to create cache directory");
496 return null;
497 }
498 FileUtils.setPermissions(
499 mCacheDir.getPath(),
500 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
501 -1, -1);
502 }
503 }
504 return mCacheDir;
505 }
506
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800507 @Override
508 public File getExternalCacheDir() {
509 synchronized (mSync) {
510 if (mExternalCacheDir == null) {
511 mExternalCacheDir = Environment.getExternalStorageAppCacheDirectory(
512 getPackageName());
513 }
514 if (!mExternalCacheDir.exists()) {
515 try {
516 (new File(Environment.getExternalStorageAndroidDataDir(),
517 ".nomedia")).createNewFile();
518 } catch (IOException e) {
519 }
520 if (!mExternalCacheDir.mkdirs()) {
521 Log.w(TAG, "Unable to create external cache directory");
522 return null;
523 }
524 }
525 return mExternalCacheDir;
526 }
527 }
528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 @Override
530 public File getFileStreamPath(String name) {
531 return makeFilename(getFilesDir(), name);
532 }
533
534 @Override
535 public String[] fileList() {
536 final String[] list = getFilesDir().list();
537 return (list != null) ? list : EMPTY_FILE_LIST;
538 }
539
540 @Override
541 public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800542 File f = validateFilePath(name, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
544 setFilePermissionsFromMode(f.getPath(), mode, 0);
545 return db;
546 }
547
548 @Override
549 public boolean deleteDatabase(String name) {
550 try {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800551 File f = validateFilePath(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 return f.delete();
553 } catch (Exception e) {
554 }
555 return false;
556 }
557
558 @Override
559 public File getDatabasePath(String name) {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800560 return validateFilePath(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 }
562
563 @Override
564 public String[] databaseList() {
565 final String[] list = getDatabasesDir().list();
566 return (list != null) ? list : EMPTY_FILE_LIST;
567 }
568
569
570 private File getDatabasesDir() {
571 synchronized (mSync) {
572 if (mDatabasesDir == null) {
573 mDatabasesDir = new File(getDataDirFile(), "databases");
574 }
575 if (mDatabasesDir.getPath().equals("databases")) {
576 mDatabasesDir = new File("/data/system");
577 }
578 return mDatabasesDir;
579 }
580 }
581
582 @Override
583 public Drawable getWallpaper() {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700584 return getWallpaperManager().getDrawable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 }
586
587 @Override
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700588 public Drawable peekWallpaper() {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700589 return getWallpaperManager().peekDrawable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 }
591
592 @Override
593 public int getWallpaperDesiredMinimumWidth() {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700594 return getWallpaperManager().getDesiredMinimumWidth();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 }
596
597 @Override
598 public int getWallpaperDesiredMinimumHeight() {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700599 return getWallpaperManager().getDesiredMinimumHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 }
601
602 @Override
603 public void setWallpaper(Bitmap bitmap) throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700604 getWallpaperManager().setBitmap(bitmap);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 }
606
607 @Override
608 public void setWallpaper(InputStream data) throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700609 getWallpaperManager().setStream(data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 }
611
612 @Override
613 public void clearWallpaper() throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700614 getWallpaperManager().clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 }
616
617 @Override
618 public void startActivity(Intent intent) {
619 if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
620 throw new AndroidRuntimeException(
621 "Calling startActivity() from outside of an Activity "
622 + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
623 + " Is this really what you want?");
624 }
625 mMainThread.getInstrumentation().execStartActivity(
626 getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
627 }
628
629 @Override
Dianne Hackbornfa82f222009-09-17 15:14:12 -0700630 public void startIntentSender(IntentSender intent,
631 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
632 throws IntentSender.SendIntentException {
633 try {
634 String resolvedType = null;
635 if (fillInIntent != null) {
636 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
637 }
638 int result = ActivityManagerNative.getDefault()
639 .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
640 fillInIntent, resolvedType, null, null,
641 0, flagsMask, flagsValues);
642 if (result == IActivityManager.START_CANCELED) {
643 throw new IntentSender.SendIntentException();
644 }
645 Instrumentation.checkStartActivityResult(result, null);
646 } catch (RemoteException e) {
647 }
648 }
649
650 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 public void sendBroadcast(Intent intent) {
652 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
653 try {
654 ActivityManagerNative.getDefault().broadcastIntent(
655 mMainThread.getApplicationThread(), intent, resolvedType, null,
656 Activity.RESULT_OK, null, null, null, false, false);
657 } catch (RemoteException e) {
658 }
659 }
660
661 @Override
662 public void sendBroadcast(Intent intent, String receiverPermission) {
663 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
664 try {
665 ActivityManagerNative.getDefault().broadcastIntent(
666 mMainThread.getApplicationThread(), intent, resolvedType, null,
667 Activity.RESULT_OK, null, null, receiverPermission, false, false);
668 } catch (RemoteException e) {
669 }
670 }
671
672 @Override
673 public void sendOrderedBroadcast(Intent intent,
674 String receiverPermission) {
675 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
676 try {
677 ActivityManagerNative.getDefault().broadcastIntent(
678 mMainThread.getApplicationThread(), intent, resolvedType, null,
679 Activity.RESULT_OK, null, null, receiverPermission, true, false);
680 } catch (RemoteException e) {
681 }
682 }
683
684 @Override
685 public void sendOrderedBroadcast(Intent intent,
686 String receiverPermission, BroadcastReceiver resultReceiver,
687 Handler scheduler, int initialCode, String initialData,
688 Bundle initialExtras) {
689 IIntentReceiver rd = null;
690 if (resultReceiver != null) {
691 if (mPackageInfo != null) {
692 if (scheduler == null) {
693 scheduler = mMainThread.getHandler();
694 }
695 rd = mPackageInfo.getReceiverDispatcher(
696 resultReceiver, getOuterContext(), scheduler,
697 mMainThread.getInstrumentation(), false);
698 } else {
699 if (scheduler == null) {
700 scheduler = mMainThread.getHandler();
701 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700702 rd = new LoadedApk.ReceiverDispatcher(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
704 }
705 }
706 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
707 try {
708 ActivityManagerNative.getDefault().broadcastIntent(
709 mMainThread.getApplicationThread(), intent, resolvedType, rd,
710 initialCode, initialData, initialExtras, receiverPermission,
711 true, false);
712 } catch (RemoteException e) {
713 }
714 }
715
716 @Override
717 public void sendStickyBroadcast(Intent intent) {
718 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
719 try {
720 ActivityManagerNative.getDefault().broadcastIntent(
721 mMainThread.getApplicationThread(), intent, resolvedType, null,
722 Activity.RESULT_OK, null, null, null, false, true);
723 } catch (RemoteException e) {
724 }
725 }
726
727 @Override
Dianne Hackbornefa199f2009-09-19 12:03:15 -0700728 public void sendStickyOrderedBroadcast(Intent intent,
729 BroadcastReceiver resultReceiver,
730 Handler scheduler, int initialCode, String initialData,
731 Bundle initialExtras) {
732 IIntentReceiver rd = null;
733 if (resultReceiver != null) {
734 if (mPackageInfo != null) {
735 if (scheduler == null) {
736 scheduler = mMainThread.getHandler();
737 }
738 rd = mPackageInfo.getReceiverDispatcher(
739 resultReceiver, getOuterContext(), scheduler,
740 mMainThread.getInstrumentation(), false);
741 } else {
742 if (scheduler == null) {
743 scheduler = mMainThread.getHandler();
744 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700745 rd = new LoadedApk.ReceiverDispatcher(
Dianne Hackbornefa199f2009-09-19 12:03:15 -0700746 resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
747 }
748 }
749 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
750 try {
751 ActivityManagerNative.getDefault().broadcastIntent(
752 mMainThread.getApplicationThread(), intent, resolvedType, rd,
753 initialCode, initialData, initialExtras, null,
754 true, true);
755 } catch (RemoteException e) {
756 }
757 }
758
759 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 public void removeStickyBroadcast(Intent intent) {
761 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
762 if (resolvedType != null) {
763 intent = new Intent(intent);
764 intent.setDataAndType(intent.getData(), resolvedType);
765 }
766 try {
767 ActivityManagerNative.getDefault().unbroadcastIntent(
768 mMainThread.getApplicationThread(), intent);
769 } catch (RemoteException e) {
770 }
771 }
772
773 @Override
774 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
775 return registerReceiver(receiver, filter, null, null);
776 }
777
778 @Override
779 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
780 String broadcastPermission, Handler scheduler) {
781 return registerReceiverInternal(receiver, filter, broadcastPermission,
782 scheduler, getOuterContext());
783 }
784
785 private Intent registerReceiverInternal(BroadcastReceiver receiver,
786 IntentFilter filter, String broadcastPermission,
787 Handler scheduler, Context context) {
788 IIntentReceiver rd = null;
789 if (receiver != null) {
790 if (mPackageInfo != null && context != null) {
791 if (scheduler == null) {
792 scheduler = mMainThread.getHandler();
793 }
794 rd = mPackageInfo.getReceiverDispatcher(
795 receiver, context, scheduler,
796 mMainThread.getInstrumentation(), true);
797 } else {
798 if (scheduler == null) {
799 scheduler = mMainThread.getHandler();
800 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700801 rd = new LoadedApk.ReceiverDispatcher(
Dianne Hackborn399cccb2010-04-13 22:57:49 -0700802 receiver, context, scheduler, null, true).getIIntentReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 }
804 }
805 try {
806 return ActivityManagerNative.getDefault().registerReceiver(
807 mMainThread.getApplicationThread(),
808 rd, filter, broadcastPermission);
809 } catch (RemoteException e) {
810 return null;
811 }
812 }
813
814 @Override
815 public void unregisterReceiver(BroadcastReceiver receiver) {
816 if (mPackageInfo != null) {
817 IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
818 getOuterContext(), receiver);
819 try {
820 ActivityManagerNative.getDefault().unregisterReceiver(rd);
821 } catch (RemoteException e) {
822 }
823 } else {
824 throw new RuntimeException("Not supported in system context");
825 }
826 }
827
828 @Override
829 public ComponentName startService(Intent service) {
830 try {
831 ComponentName cn = ActivityManagerNative.getDefault().startService(
832 mMainThread.getApplicationThread(), service,
833 service.resolveTypeIfNeeded(getContentResolver()));
834 if (cn != null && cn.getPackageName().equals("!")) {
835 throw new SecurityException(
836 "Not allowed to start service " + service
837 + " without permission " + cn.getClassName());
838 }
839 return cn;
840 } catch (RemoteException e) {
841 return null;
842 }
843 }
844
845 @Override
846 public boolean stopService(Intent service) {
847 try {
848 int res = ActivityManagerNative.getDefault().stopService(
849 mMainThread.getApplicationThread(), service,
850 service.resolveTypeIfNeeded(getContentResolver()));
851 if (res < 0) {
852 throw new SecurityException(
853 "Not allowed to stop service " + service);
854 }
855 return res != 0;
856 } catch (RemoteException e) {
857 return false;
858 }
859 }
860
861 @Override
862 public boolean bindService(Intent service, ServiceConnection conn,
863 int flags) {
864 IServiceConnection sd;
865 if (mPackageInfo != null) {
866 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
867 mMainThread.getHandler(), flags);
868 } else {
869 throw new RuntimeException("Not supported in system context");
870 }
871 try {
872 int res = ActivityManagerNative.getDefault().bindService(
873 mMainThread.getApplicationThread(), getActivityToken(),
874 service, service.resolveTypeIfNeeded(getContentResolver()),
875 sd, flags);
876 if (res < 0) {
877 throw new SecurityException(
878 "Not allowed to bind to service " + service);
879 }
880 return res != 0;
881 } catch (RemoteException e) {
882 return false;
883 }
884 }
885
886 @Override
887 public void unbindService(ServiceConnection conn) {
888 if (mPackageInfo != null) {
889 IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
890 getOuterContext(), conn);
891 try {
892 ActivityManagerNative.getDefault().unbindService(sd);
893 } catch (RemoteException e) {
894 }
895 } else {
896 throw new RuntimeException("Not supported in system context");
897 }
898 }
899
900 @Override
901 public boolean startInstrumentation(ComponentName className,
902 String profileFile, Bundle arguments) {
903 try {
904 return ActivityManagerNative.getDefault().startInstrumentation(
905 className, profileFile, 0, arguments, null);
906 } catch (RemoteException e) {
907 // System has crashed, nothing we can do.
908 }
909 return false;
910 }
911
912 @Override
913 public Object getSystemService(String name) {
914 if (WINDOW_SERVICE.equals(name)) {
915 return WindowManagerImpl.getDefault();
916 } else if (LAYOUT_INFLATER_SERVICE.equals(name)) {
917 synchronized (mSync) {
918 LayoutInflater inflater = mLayoutInflater;
919 if (inflater != null) {
920 return inflater;
921 }
922 mLayoutInflater = inflater =
923 PolicyManager.makeNewLayoutInflater(getOuterContext());
924 return inflater;
925 }
926 } else if (ACTIVITY_SERVICE.equals(name)) {
927 return getActivityManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700928 } else if (INPUT_METHOD_SERVICE.equals(name)) {
929 return InputMethodManager.getInstance(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 } else if (ALARM_SERVICE.equals(name)) {
931 return getAlarmManager();
Fred Quintana60307342009-03-24 22:48:12 -0700932 } else if (ACCOUNT_SERVICE.equals(name)) {
933 return getAccountManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 } else if (POWER_SERVICE.equals(name)) {
935 return getPowerManager();
936 } else if (CONNECTIVITY_SERVICE.equals(name)) {
937 return getConnectivityManager();
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700938 } else if (THROTTLE_SERVICE.equals(name)) {
939 return getThrottleManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 } else if (WIFI_SERVICE.equals(name)) {
941 return getWifiManager();
942 } else if (NOTIFICATION_SERVICE.equals(name)) {
943 return getNotificationManager();
944 } else if (KEYGUARD_SERVICE.equals(name)) {
945 return new KeyguardManager();
svetoslavganov75986cf2009-05-14 22:28:01 -0700946 } else if (ACCESSIBILITY_SERVICE.equals(name)) {
947 return AccessibilityManager.getInstance(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 } else if (LOCATION_SERVICE.equals(name)) {
949 return getLocationManager();
950 } else if (SEARCH_SERVICE.equals(name)) {
951 return getSearchManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700952 } else if (SENSOR_SERVICE.equals(name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 return getSensorManager();
San Mehatc9d81752010-02-01 10:23:27 -0800954 } else if (STORAGE_SERVICE.equals(name)) {
955 return getStorageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 } else if (VIBRATOR_SERVICE.equals(name)) {
957 return getVibrator();
958 } else if (STATUS_BAR_SERVICE.equals(name)) {
959 synchronized (mSync) {
960 if (mStatusBarManager == null) {
961 mStatusBarManager = new StatusBarManager(getOuterContext());
962 }
963 return mStatusBarManager;
964 }
965 } else if (AUDIO_SERVICE.equals(name)) {
966 return getAudioManager();
967 } else if (TELEPHONY_SERVICE.equals(name)) {
968 return getTelephonyManager();
969 } else if (CLIPBOARD_SERVICE.equals(name)) {
970 return getClipboardManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700971 } else if (WALLPAPER_SERVICE.equals(name)) {
972 return getWallpaperManager();
Dan Egnor95240272009-10-27 18:23:39 -0700973 } else if (DROPBOX_SERVICE.equals(name)) {
Dan Egnorf18a01c2009-11-12 11:32:50 -0800974 return getDropBoxManager();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800975 } else if (DEVICE_POLICY_SERVICE.equals(name)) {
976 return getDevicePolicyManager();
Tobias Haamel69fb5742010-02-22 21:54:05 +0100977 } else if (UI_MODE_SERVICE.equals(name)) {
Tobias Haamel53332882010-02-18 16:15:43 -0800978 return getUiModeManager();
Steve Howarda2709362010-07-02 17:12:48 -0700979 } else if (DOWNLOAD_SERVICE.equals(name)) {
980 return getDownloadManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 }
982
983 return null;
984 }
985
Fred Quintana60307342009-03-24 22:48:12 -0700986 private AccountManager getAccountManager() {
Fred Quintanae00a3112009-09-22 15:13:30 -0700987 synchronized (mSync) {
988 if (mAccountManager == null) {
Fred Quintana60307342009-03-24 22:48:12 -0700989 IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
990 IAccountManager service = IAccountManager.Stub.asInterface(b);
Fred Quintanae00a3112009-09-22 15:13:30 -0700991 mAccountManager = new AccountManager(this, service);
Fred Quintana60307342009-03-24 22:48:12 -0700992 }
Fred Quintanae00a3112009-09-22 15:13:30 -0700993 return mAccountManager;
Fred Quintana60307342009-03-24 22:48:12 -0700994 }
Fred Quintana60307342009-03-24 22:48:12 -0700995 }
996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 private ActivityManager getActivityManager() {
998 synchronized (mSync) {
999 if (mActivityManager == null) {
1000 mActivityManager = new ActivityManager(getOuterContext(),
1001 mMainThread.getHandler());
1002 }
1003 }
1004 return mActivityManager;
1005 }
1006
1007 private AlarmManager getAlarmManager() {
1008 synchronized (sSync) {
1009 if (sAlarmManager == null) {
1010 IBinder b = ServiceManager.getService(ALARM_SERVICE);
1011 IAlarmManager service = IAlarmManager.Stub.asInterface(b);
1012 sAlarmManager = new AlarmManager(service);
1013 }
1014 }
1015 return sAlarmManager;
1016 }
1017
1018 private PowerManager getPowerManager() {
1019 synchronized (sSync) {
1020 if (sPowerManager == null) {
1021 IBinder b = ServiceManager.getService(POWER_SERVICE);
1022 IPowerManager service = IPowerManager.Stub.asInterface(b);
1023 sPowerManager = new PowerManager(service, mMainThread.getHandler());
1024 }
1025 }
1026 return sPowerManager;
1027 }
1028
1029 private ConnectivityManager getConnectivityManager()
1030 {
1031 synchronized (sSync) {
1032 if (sConnectivityManager == null) {
1033 IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
1034 IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
1035 sConnectivityManager = new ConnectivityManager(service);
1036 }
1037 }
1038 return sConnectivityManager;
1039 }
1040
Irfan Sheriffc9b68512010-04-08 14:12:33 -07001041 private ThrottleManager getThrottleManager()
1042 {
1043 synchronized (sSync) {
1044 if (sThrottleManager == null) {
1045 IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
1046 IThrottleManager service = IThrottleManager.Stub.asInterface(b);
1047 sThrottleManager = new ThrottleManager(service);
1048 }
1049 }
1050 return sThrottleManager;
1051 }
1052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 private WifiManager getWifiManager()
1054 {
1055 synchronized (sSync) {
1056 if (sWifiManager == null) {
1057 IBinder b = ServiceManager.getService(WIFI_SERVICE);
1058 IWifiManager service = IWifiManager.Stub.asInterface(b);
1059 sWifiManager = new WifiManager(service, mMainThread.getHandler());
1060 }
1061 }
1062 return sWifiManager;
1063 }
1064
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001065 private NotificationManager getNotificationManager() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 synchronized (mSync) {
1067 if (mNotificationManager == null) {
1068 mNotificationManager = new NotificationManager(
1069 new ContextThemeWrapper(getOuterContext(), com.android.internal.R.style.Theme_Dialog),
1070 mMainThread.getHandler());
1071 }
1072 }
1073 return mNotificationManager;
1074 }
1075
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001076 private WallpaperManager getWallpaperManager() {
1077 synchronized (mSync) {
1078 if (mWallpaperManager == null) {
1079 mWallpaperManager = new WallpaperManager(getOuterContext(),
1080 mMainThread.getHandler());
1081 }
1082 }
1083 return mWallpaperManager;
1084 }
1085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 private TelephonyManager getTelephonyManager() {
1087 synchronized (mSync) {
1088 if (mTelephonyManager == null) {
1089 mTelephonyManager = new TelephonyManager(getOuterContext());
1090 }
1091 }
1092 return mTelephonyManager;
1093 }
1094
1095 private ClipboardManager getClipboardManager() {
1096 synchronized (mSync) {
1097 if (mClipboardManager == null) {
1098 mClipboardManager = new ClipboardManager(getOuterContext(),
1099 mMainThread.getHandler());
1100 }
1101 }
1102 return mClipboardManager;
1103 }
1104
1105 private LocationManager getLocationManager() {
1106 synchronized (sSync) {
1107 if (sLocationManager == null) {
1108 IBinder b = ServiceManager.getService(LOCATION_SERVICE);
1109 ILocationManager service = ILocationManager.Stub.asInterface(b);
1110 sLocationManager = new LocationManager(service);
1111 }
1112 }
1113 return sLocationManager;
1114 }
1115
1116 private SearchManager getSearchManager() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 synchronized (mSync) {
1118 if (mSearchManager == null) {
1119 mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
1120 }
1121 }
1122 return mSearchManager;
1123 }
1124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 private SensorManager getSensorManager() {
1126 synchronized (mSync) {
1127 if (mSensorManager == null) {
1128 mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());
1129 }
1130 }
1131 return mSensorManager;
1132 }
1133
San Mehatc9d81752010-02-01 10:23:27 -08001134 private StorageManager getStorageManager() {
1135 synchronized (mSync) {
1136 if (mStorageManager == null) {
1137 try {
1138 mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
1139 } catch (RemoteException rex) {
1140 Log.e(TAG, "Failed to create StorageManager", rex);
1141 mStorageManager = null;
1142 }
1143 }
1144 }
1145 return mStorageManager;
1146 }
1147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 private Vibrator getVibrator() {
1149 synchronized (mSync) {
1150 if (mVibrator == null) {
1151 mVibrator = new Vibrator();
1152 }
1153 }
1154 return mVibrator;
1155 }
Dan Egnor95240272009-10-27 18:23:39 -07001156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 private AudioManager getAudioManager()
1158 {
1159 if (mAudioManager == null) {
1160 mAudioManager = new AudioManager(this);
1161 }
1162 return mAudioManager;
1163 }
1164
Brad Fitzpatrick438d0592010-06-10 12:19:19 -07001165 /* package */ static DropBoxManager createDropBoxManager() {
1166 IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
1167 IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
1168 return new DropBoxManager(service);
1169 }
1170
Dan Egnorf18a01c2009-11-12 11:32:50 -08001171 private DropBoxManager getDropBoxManager() {
Dan Egnor95240272009-10-27 18:23:39 -07001172 synchronized (mSync) {
Dan Egnorf18a01c2009-11-12 11:32:50 -08001173 if (mDropBoxManager == null) {
Brad Fitzpatrick438d0592010-06-10 12:19:19 -07001174 mDropBoxManager = createDropBoxManager();
Dan Egnor95240272009-10-27 18:23:39 -07001175 }
1176 }
Dan Egnorf18a01c2009-11-12 11:32:50 -08001177 return mDropBoxManager;
Dan Egnor95240272009-10-27 18:23:39 -07001178 }
1179
Dianne Hackbornd6847842010-01-12 18:14:19 -08001180 private DevicePolicyManager getDevicePolicyManager() {
1181 synchronized (mSync) {
1182 if (mDevicePolicyManager == null) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001183 mDevicePolicyManager = DevicePolicyManager.create(this,
Dianne Hackbornd6847842010-01-12 18:14:19 -08001184 mMainThread.getHandler());
1185 }
1186 }
1187 return mDevicePolicyManager;
1188 }
1189
Tobias Haamel53332882010-02-18 16:15:43 -08001190 private UiModeManager getUiModeManager() {
1191 synchronized (mSync) {
1192 if (mUiModeManager == null) {
1193 mUiModeManager = new UiModeManager();
1194 }
1195 }
1196 return mUiModeManager;
1197 }
1198
Steve Howarda2709362010-07-02 17:12:48 -07001199 private DownloadManager getDownloadManager() {
1200 synchronized (mSync) {
1201 if (mDownloadManager == null) {
Steve Howardb8e07a52010-07-21 14:53:21 -07001202 mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
Steve Howarda2709362010-07-02 17:12:48 -07001203 }
1204 }
1205 return mDownloadManager;
1206 }
1207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 @Override
1209 public int checkPermission(String permission, int pid, int uid) {
1210 if (permission == null) {
1211 throw new IllegalArgumentException("permission is null");
1212 }
1213
1214 if (!Process.supportsProcesses()) {
1215 return PackageManager.PERMISSION_GRANTED;
1216 }
1217 try {
1218 return ActivityManagerNative.getDefault().checkPermission(
1219 permission, pid, uid);
1220 } catch (RemoteException e) {
1221 return PackageManager.PERMISSION_DENIED;
1222 }
1223 }
1224
1225 @Override
1226 public int checkCallingPermission(String permission) {
1227 if (permission == null) {
1228 throw new IllegalArgumentException("permission is null");
1229 }
1230
1231 if (!Process.supportsProcesses()) {
1232 return PackageManager.PERMISSION_GRANTED;
1233 }
1234 int pid = Binder.getCallingPid();
1235 if (pid != Process.myPid()) {
1236 return checkPermission(permission, pid,
1237 Binder.getCallingUid());
1238 }
1239 return PackageManager.PERMISSION_DENIED;
1240 }
1241
1242 @Override
1243 public int checkCallingOrSelfPermission(String permission) {
1244 if (permission == null) {
1245 throw new IllegalArgumentException("permission is null");
1246 }
1247
1248 return checkPermission(permission, Binder.getCallingPid(),
1249 Binder.getCallingUid());
1250 }
1251
1252 private void enforce(
1253 String permission, int resultOfCheck,
1254 boolean selfToo, int uid, String message) {
1255 if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1256 throw new SecurityException(
1257 (message != null ? (message + ": ") : "") +
1258 (selfToo
1259 ? "Neither user " + uid + " nor current process has "
1260 : "User " + uid + " does not have ") +
1261 permission +
1262 ".");
1263 }
1264 }
1265
1266 public void enforcePermission(
1267 String permission, int pid, int uid, String message) {
1268 enforce(permission,
1269 checkPermission(permission, pid, uid),
1270 false,
1271 uid,
1272 message);
1273 }
1274
1275 public void enforceCallingPermission(String permission, String message) {
1276 enforce(permission,
1277 checkCallingPermission(permission),
1278 false,
1279 Binder.getCallingUid(),
1280 message);
1281 }
1282
1283 public void enforceCallingOrSelfPermission(
1284 String permission, String message) {
1285 enforce(permission,
1286 checkCallingOrSelfPermission(permission),
1287 true,
1288 Binder.getCallingUid(),
1289 message);
1290 }
1291
1292 @Override
1293 public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
1294 try {
1295 ActivityManagerNative.getDefault().grantUriPermission(
1296 mMainThread.getApplicationThread(), toPackage, uri,
1297 modeFlags);
1298 } catch (RemoteException e) {
1299 }
1300 }
1301
1302 @Override
1303 public void revokeUriPermission(Uri uri, int modeFlags) {
1304 try {
1305 ActivityManagerNative.getDefault().revokeUriPermission(
1306 mMainThread.getApplicationThread(), uri,
1307 modeFlags);
1308 } catch (RemoteException e) {
1309 }
1310 }
1311
1312 @Override
1313 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
1314 if (!Process.supportsProcesses()) {
1315 return PackageManager.PERMISSION_GRANTED;
1316 }
1317 try {
1318 return ActivityManagerNative.getDefault().checkUriPermission(
1319 uri, pid, uid, modeFlags);
1320 } catch (RemoteException e) {
1321 return PackageManager.PERMISSION_DENIED;
1322 }
1323 }
1324
1325 @Override
1326 public int checkCallingUriPermission(Uri uri, int modeFlags) {
1327 if (!Process.supportsProcesses()) {
1328 return PackageManager.PERMISSION_GRANTED;
1329 }
1330 int pid = Binder.getCallingPid();
1331 if (pid != Process.myPid()) {
1332 return checkUriPermission(uri, pid,
1333 Binder.getCallingUid(), modeFlags);
1334 }
1335 return PackageManager.PERMISSION_DENIED;
1336 }
1337
1338 @Override
1339 public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
1340 return checkUriPermission(uri, Binder.getCallingPid(),
1341 Binder.getCallingUid(), modeFlags);
1342 }
1343
1344 @Override
1345 public int checkUriPermission(Uri uri, String readPermission,
1346 String writePermission, int pid, int uid, int modeFlags) {
Mitsuru Oshima569076c2009-07-02 20:06:08 -07001347 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission="
1349 + readPermission + " writePermission=" + writePermission
1350 + " pid=" + pid + " uid=" + uid + " mode" + modeFlags);
1351 }
1352 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
1353 if (readPermission == null
1354 || checkPermission(readPermission, pid, uid)
1355 == PackageManager.PERMISSION_GRANTED) {
1356 return PackageManager.PERMISSION_GRANTED;
1357 }
1358 }
1359 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
1360 if (writePermission == null
1361 || checkPermission(writePermission, pid, uid)
1362 == PackageManager.PERMISSION_GRANTED) {
1363 return PackageManager.PERMISSION_GRANTED;
1364 }
1365 }
1366 return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
1367 : PackageManager.PERMISSION_DENIED;
1368 }
1369
1370 private String uriModeFlagToString(int uriModeFlags) {
1371 switch (uriModeFlags) {
1372 case Intent.FLAG_GRANT_READ_URI_PERMISSION |
1373 Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1374 return "read and write";
1375 case Intent.FLAG_GRANT_READ_URI_PERMISSION:
1376 return "read";
1377 case Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1378 return "write";
1379 }
1380 throw new IllegalArgumentException(
1381 "Unknown permission mode flags: " + uriModeFlags);
1382 }
1383
1384 private void enforceForUri(
1385 int modeFlags, int resultOfCheck, boolean selfToo,
1386 int uid, Uri uri, String message) {
1387 if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1388 throw new SecurityException(
1389 (message != null ? (message + ": ") : "") +
1390 (selfToo
1391 ? "Neither user " + uid + " nor current process has "
1392 : "User " + uid + " does not have ") +
1393 uriModeFlagToString(modeFlags) +
1394 " permission on " +
1395 uri +
1396 ".");
1397 }
1398 }
1399
1400 public void enforceUriPermission(
1401 Uri uri, int pid, int uid, int modeFlags, String message) {
1402 enforceForUri(
1403 modeFlags, checkUriPermission(uri, pid, uid, modeFlags),
1404 false, uid, uri, message);
1405 }
1406
1407 public void enforceCallingUriPermission(
1408 Uri uri, int modeFlags, String message) {
1409 enforceForUri(
1410 modeFlags, checkCallingUriPermission(uri, modeFlags),
1411 false, Binder.getCallingUid(), uri, message);
1412 }
1413
1414 public void enforceCallingOrSelfUriPermission(
1415 Uri uri, int modeFlags, String message) {
1416 enforceForUri(
1417 modeFlags,
1418 checkCallingOrSelfUriPermission(uri, modeFlags), true,
1419 Binder.getCallingUid(), uri, message);
1420 }
1421
1422 public void enforceUriPermission(
1423 Uri uri, String readPermission, String writePermission,
1424 int pid, int uid, int modeFlags, String message) {
1425 enforceForUri(modeFlags,
1426 checkUriPermission(
1427 uri, readPermission, writePermission, pid, uid,
1428 modeFlags),
1429 false,
1430 uid,
1431 uri,
1432 message);
1433 }
1434
1435 @Override
1436 public Context createPackageContext(String packageName, int flags)
1437 throws PackageManager.NameNotFoundException {
1438 if (packageName.equals("system") || packageName.equals("android")) {
Dianne Hackborn21556372010-02-04 16:34:40 -08001439 return new ContextImpl(mMainThread.getSystemContext());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 }
1441
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001442 LoadedApk pi =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 mMainThread.getPackageInfo(packageName, flags);
1444 if (pi != null) {
Dianne Hackborn21556372010-02-04 16:34:40 -08001445 ContextImpl c = new ContextImpl();
Romain Guy870e09f2009-07-06 16:35:25 -07001446 c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001447 c.init(pi, null, mMainThread, mResources);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 if (c.mResources != null) {
1449 return c;
1450 }
1451 }
1452
1453 // Should be a better exception.
1454 throw new PackageManager.NameNotFoundException(
1455 "Application package " + packageName + " not found");
1456 }
1457
Romain Guy870e09f2009-07-06 16:35:25 -07001458 @Override
1459 public boolean isRestricted() {
1460 return mRestricted;
1461 }
1462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 private File getDataDirFile() {
1464 if (mPackageInfo != null) {
1465 return mPackageInfo.getDataDirFile();
1466 }
1467 throw new RuntimeException("Not supported in system context");
1468 }
1469
1470 @Override
1471 public File getDir(String name, int mode) {
1472 name = "app_" + name;
1473 File file = makeFilename(getDataDirFile(), name);
1474 if (!file.exists()) {
1475 file.mkdir();
1476 setFilePermissionsFromMode(file.getPath(), mode,
1477 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH);
1478 }
1479 return file;
1480 }
1481
Dianne Hackborn21556372010-02-04 16:34:40 -08001482 static ContextImpl createSystemContext(ActivityThread mainThread) {
1483 ContextImpl context = new ContextImpl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 context.init(Resources.getSystem(), mainThread);
1485 return context;
1486 }
1487
Dianne Hackborn21556372010-02-04 16:34:40 -08001488 ContextImpl() {
Carl Shapiro82fe5642010-02-24 00:14:23 -08001489 // For debug only
1490 //++sInstanceCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 mOuterContext = this;
1492 }
1493
1494 /**
1495 * Create a new ApplicationContext from an existing one. The new one
1496 * works and operates the same as the one it is copying.
1497 *
1498 * @param context Existing application context.
1499 */
Dianne Hackborn21556372010-02-04 16:34:40 -08001500 public ContextImpl(ContextImpl context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 ++sInstanceCount;
1502 mPackageInfo = context.mPackageInfo;
1503 mResources = context.mResources;
1504 mMainThread = context.mMainThread;
1505 mContentResolver = context.mContentResolver;
1506 mOuterContext = this;
1507 }
1508
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001509 final void init(LoadedApk packageInfo,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 IBinder activityToken, ActivityThread mainThread) {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001511 init(packageInfo, activityToken, mainThread, null);
1512 }
1513
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001514 final void init(LoadedApk packageInfo,
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001515 IBinder activityToken, ActivityThread mainThread,
1516 Resources container) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 mPackageInfo = packageInfo;
1518 mResources = mPackageInfo.getResources(mainThread);
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001519
Dianne Hackborn559a7872010-04-07 18:19:41 -07001520 if (mResources != null && container != null
1521 && container.getCompatibilityInfo().applicationScale !=
1522 mResources.getCompatibilityInfo().applicationScale) {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001523 if (DEBUG) {
1524 Log.d(TAG, "loaded context has different scaling. Using container's" +
1525 " compatiblity info:" + container.getDisplayMetrics());
1526 }
1527 mResources = mainThread.getTopLevelResources(
1528 mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
1529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 mMainThread = mainThread;
1531 mContentResolver = new ApplicationContentResolver(this, mainThread);
1532
1533 setActivityToken(activityToken);
1534 }
1535
1536 final void init(Resources resources, ActivityThread mainThread) {
1537 mPackageInfo = null;
1538 mResources = resources;
1539 mMainThread = mainThread;
1540 mContentResolver = new ApplicationContentResolver(this, mainThread);
1541 }
1542
1543 final void scheduleFinalCleanup(String who, String what) {
1544 mMainThread.scheduleContextCleanup(this, who, what);
1545 }
1546
1547 final void performFinalCleanup(String who, String what) {
1548 //Log.i(TAG, "Cleanup up context: " + this);
1549 mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
1550 }
1551
1552 final Context getReceiverRestrictedContext() {
1553 if (mReceiverRestrictedContext != null) {
1554 return mReceiverRestrictedContext;
1555 }
1556 return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
1557 }
1558
1559 final void setActivityToken(IBinder token) {
1560 mActivityToken = token;
1561 }
1562
1563 final void setOuterContext(Context context) {
1564 mOuterContext = context;
1565 }
1566
1567 final Context getOuterContext() {
1568 return mOuterContext;
1569 }
1570
1571 final IBinder getActivityToken() {
1572 return mActivityToken;
1573 }
1574
1575 private static void setFilePermissionsFromMode(String name, int mode,
1576 int extraPermissions) {
1577 int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
1578 |FileUtils.S_IRGRP|FileUtils.S_IWGRP
1579 |extraPermissions;
1580 if ((mode&MODE_WORLD_READABLE) != 0) {
1581 perms |= FileUtils.S_IROTH;
1582 }
1583 if ((mode&MODE_WORLD_WRITEABLE) != 0) {
1584 perms |= FileUtils.S_IWOTH;
1585 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -07001586 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode)
1588 + ", perms=0x" + Integer.toHexString(perms));
1589 }
1590 FileUtils.setPermissions(name, perms, -1, -1);
1591 }
1592
Oscar Montemayora8529f62009-11-18 10:14:20 -08001593 private File validateFilePath(String name, boolean createDirectory) {
1594 File dir;
1595 File f;
1596
1597 if (name.charAt(0) == File.separatorChar) {
1598 String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
1599 dir = new File(dirPath);
1600 name = name.substring(name.lastIndexOf(File.separatorChar));
1601 f = new File(dir, name);
1602 } else {
1603 dir = getDatabasesDir();
1604 f = makeFilename(dir, name);
1605 }
1606
1607 if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
1608 FileUtils.setPermissions(dir.getPath(),
1609 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1610 -1, -1);
1611 }
1612
1613 return f;
1614 }
1615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 private File makeFilename(File base, String name) {
1617 if (name.indexOf(File.separatorChar) < 0) {
1618 return new File(base, name);
1619 }
1620 throw new IllegalArgumentException(
Oscar Montemayora8529f62009-11-18 10:14:20 -08001621 "File " + name + " contains a path separator");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 }
1623
1624 // ----------------------------------------------------------------------
1625 // ----------------------------------------------------------------------
1626 // ----------------------------------------------------------------------
1627
1628 private static final class ApplicationContentResolver extends ContentResolver {
1629 public ApplicationContentResolver(Context context,
1630 ActivityThread mainThread)
1631 {
1632 super(context);
1633 mMainThread = mainThread;
1634 }
1635
1636 @Override
1637 protected IContentProvider acquireProvider(Context context, String name)
1638 {
1639 return mMainThread.acquireProvider(context, name);
1640 }
1641
1642 @Override
1643 public boolean releaseProvider(IContentProvider provider)
1644 {
1645 return mMainThread.releaseProvider(provider);
1646 }
1647
1648 private final ActivityThread mMainThread;
1649 }
1650
1651 // ----------------------------------------------------------------------
1652 // ----------------------------------------------------------------------
1653 // ----------------------------------------------------------------------
1654
1655 /*package*/
1656 static final class ApplicationPackageManager extends PackageManager {
1657 @Override
1658 public PackageInfo getPackageInfo(String packageName, int flags)
1659 throws NameNotFoundException {
1660 try {
1661 PackageInfo pi = mPM.getPackageInfo(packageName, flags);
1662 if (pi != null) {
1663 return pi;
1664 }
1665 } catch (RemoteException e) {
1666 throw new RuntimeException("Package manager has died", e);
1667 }
1668
1669 throw new NameNotFoundException(packageName);
1670 }
1671
Mihai Predaeae850c2009-05-13 10:13:48 +02001672 @Override
Dianne Hackborn47096932010-02-11 15:57:09 -08001673 public String[] currentToCanonicalPackageNames(String[] names) {
1674 try {
1675 return mPM.currentToCanonicalPackageNames(names);
1676 } catch (RemoteException e) {
1677 throw new RuntimeException("Package manager has died", e);
1678 }
1679 }
1680
1681 @Override
1682 public String[] canonicalToCurrentPackageNames(String[] names) {
1683 try {
1684 return mPM.canonicalToCurrentPackageNames(names);
1685 } catch (RemoteException e) {
1686 throw new RuntimeException("Package manager has died", e);
1687 }
1688 }
1689
1690 @Override
Mihai Predaeae850c2009-05-13 10:13:48 +02001691 public Intent getLaunchIntentForPackage(String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 // First see if the package has an INFO activity; the existence of
1693 // such an activity is implied to be the desired front-door for the
1694 // overall package (such as if it has multiple launcher entries).
Mihai Predaeae850c2009-05-13 10:13:48 +02001695 Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1696 intentToResolve.addCategory(Intent.CATEGORY_INFO);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07001697 intentToResolve.setPackage(packageName);
1698 ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0);
Mihai Predaeae850c2009-05-13 10:13:48 +02001699
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 // Otherwise, try to find a main launcher activity.
Mihai Predaeae850c2009-05-13 10:13:48 +02001701 if (resolveInfo == null) {
1702 // reuse the intent instance
1703 intentToResolve.removeCategory(Intent.CATEGORY_INFO);
1704 intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07001705 intentToResolve.setPackage(packageName);
1706 resolveInfo = resolveActivity(intentToResolve, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 }
Mihai Predaeae850c2009-05-13 10:13:48 +02001708 if (resolveInfo == null) {
1709 return null;
1710 }
1711 Intent intent = new Intent(Intent.ACTION_MAIN);
1712 intent.setClassName(packageName, resolveInfo.activityInfo.name);
1713 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1714 return intent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 }
Mihai Predaeae850c2009-05-13 10:13:48 +02001716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 @Override
1718 public int[] getPackageGids(String packageName)
1719 throws NameNotFoundException {
1720 try {
1721 int[] gids = mPM.getPackageGids(packageName);
1722 if (gids == null || gids.length > 0) {
1723 return gids;
1724 }
1725 } catch (RemoteException e) {
1726 throw new RuntimeException("Package manager has died", e);
1727 }
1728
1729 throw new NameNotFoundException(packageName);
1730 }
1731
1732 @Override
1733 public PermissionInfo getPermissionInfo(String name, int flags)
1734 throws NameNotFoundException {
1735 try {
1736 PermissionInfo pi = mPM.getPermissionInfo(name, flags);
1737 if (pi != null) {
1738 return pi;
1739 }
1740 } catch (RemoteException e) {
1741 throw new RuntimeException("Package manager has died", e);
1742 }
1743
1744 throw new NameNotFoundException(name);
1745 }
1746
1747 @Override
1748 public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
1749 throws NameNotFoundException {
1750 try {
1751 List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
1752 if (pi != null) {
1753 return pi;
1754 }
1755 } catch (RemoteException e) {
1756 throw new RuntimeException("Package manager has died", e);
1757 }
1758
1759 throw new NameNotFoundException(group);
1760 }
1761
1762 @Override
1763 public PermissionGroupInfo getPermissionGroupInfo(String name,
1764 int flags) throws NameNotFoundException {
1765 try {
1766 PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
1767 if (pgi != null) {
1768 return pgi;
1769 }
1770 } catch (RemoteException e) {
1771 throw new RuntimeException("Package manager has died", e);
1772 }
1773
1774 throw new NameNotFoundException(name);
1775 }
1776
1777 @Override
1778 public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
1779 try {
1780 return mPM.getAllPermissionGroups(flags);
1781 } catch (RemoteException e) {
1782 throw new RuntimeException("Package manager has died", e);
1783 }
1784 }
1785
1786 @Override
1787 public ApplicationInfo getApplicationInfo(String packageName, int flags)
1788 throws NameNotFoundException {
1789 try {
1790 ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
1791 if (ai != null) {
1792 return ai;
1793 }
1794 } catch (RemoteException e) {
1795 throw new RuntimeException("Package manager has died", e);
1796 }
1797
1798 throw new NameNotFoundException(packageName);
1799 }
1800
1801 @Override
1802 public ActivityInfo getActivityInfo(ComponentName className, int flags)
1803 throws NameNotFoundException {
1804 try {
1805 ActivityInfo ai = mPM.getActivityInfo(className, flags);
1806 if (ai != null) {
1807 return ai;
1808 }
1809 } catch (RemoteException e) {
1810 throw new RuntimeException("Package manager has died", e);
1811 }
1812
1813 throw new NameNotFoundException(className.toString());
1814 }
1815
1816 @Override
1817 public ActivityInfo getReceiverInfo(ComponentName className, int flags)
1818 throws NameNotFoundException {
1819 try {
1820 ActivityInfo ai = mPM.getReceiverInfo(className, flags);
1821 if (ai != null) {
1822 return ai;
1823 }
1824 } catch (RemoteException e) {
1825 throw new RuntimeException("Package manager has died", e);
1826 }
1827
1828 throw new NameNotFoundException(className.toString());
1829 }
1830
1831 @Override
1832 public ServiceInfo getServiceInfo(ComponentName className, int flags)
1833 throws NameNotFoundException {
1834 try {
1835 ServiceInfo si = mPM.getServiceInfo(className, flags);
1836 if (si != null) {
1837 return si;
1838 }
1839 } catch (RemoteException e) {
1840 throw new RuntimeException("Package manager has died", e);
1841 }
1842
1843 throw new NameNotFoundException(className.toString());
1844 }
1845
1846 @Override
Dianne Hackborn361199b2010-08-30 17:42:07 -07001847 public ProviderInfo getProviderInfo(ComponentName className, int flags)
1848 throws NameNotFoundException {
1849 try {
1850 ProviderInfo pi = mPM.getProviderInfo(className, flags);
1851 if (pi != null) {
1852 return pi;
1853 }
1854 } catch (RemoteException e) {
1855 throw new RuntimeException("Package manager has died", e);
1856 }
1857
1858 throw new NameNotFoundException(className.toString());
1859 }
1860
1861 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 public String[] getSystemSharedLibraryNames() {
1863 try {
1864 return mPM.getSystemSharedLibraryNames();
1865 } catch (RemoteException e) {
1866 throw new RuntimeException("Package manager has died", e);
1867 }
1868 }
1869
1870 @Override
Dianne Hackborn49237342009-08-27 20:08:01 -07001871 public FeatureInfo[] getSystemAvailableFeatures() {
1872 try {
1873 return mPM.getSystemAvailableFeatures();
1874 } catch (RemoteException e) {
1875 throw new RuntimeException("Package manager has died", e);
1876 }
1877 }
1878
1879 @Override
Dianne Hackborn039c68e2009-09-26 16:39:23 -07001880 public boolean hasSystemFeature(String name) {
1881 try {
1882 return mPM.hasSystemFeature(name);
1883 } catch (RemoteException e) {
1884 throw new RuntimeException("Package manager has died", e);
1885 }
1886 }
1887
1888 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 public int checkPermission(String permName, String pkgName) {
1890 try {
1891 return mPM.checkPermission(permName, pkgName);
1892 } catch (RemoteException e) {
1893 throw new RuntimeException("Package manager has died", e);
1894 }
1895 }
1896
1897 @Override
1898 public boolean addPermission(PermissionInfo info) {
1899 try {
1900 return mPM.addPermission(info);
1901 } catch (RemoteException e) {
1902 throw new RuntimeException("Package manager has died", e);
1903 }
1904 }
1905
1906 @Override
Dianne Hackbornd7c09682010-03-30 10:42:20 -07001907 public boolean addPermissionAsync(PermissionInfo info) {
1908 try {
1909 return mPM.addPermissionAsync(info);
1910 } catch (RemoteException e) {
1911 throw new RuntimeException("Package manager has died", e);
1912 }
1913 }
1914
1915 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 public void removePermission(String name) {
1917 try {
1918 mPM.removePermission(name);
1919 } catch (RemoteException e) {
1920 throw new RuntimeException("Package manager has died", e);
1921 }
1922 }
1923
1924 @Override
1925 public int checkSignatures(String pkg1, String pkg2) {
1926 try {
1927 return mPM.checkSignatures(pkg1, pkg2);
1928 } catch (RemoteException e) {
1929 throw new RuntimeException("Package manager has died", e);
1930 }
1931 }
1932
1933 @Override
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001934 public int checkSignatures(int uid1, int uid2) {
1935 try {
1936 return mPM.checkUidSignatures(uid1, uid2);
1937 } catch (RemoteException e) {
1938 throw new RuntimeException("Package manager has died", e);
1939 }
1940 }
1941
1942 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 public String[] getPackagesForUid(int uid) {
1944 try {
1945 return mPM.getPackagesForUid(uid);
1946 } catch (RemoteException e) {
1947 throw new RuntimeException("Package manager has died", e);
1948 }
1949 }
1950
1951 @Override
1952 public String getNameForUid(int uid) {
1953 try {
1954 return mPM.getNameForUid(uid);
1955 } catch (RemoteException e) {
1956 throw new RuntimeException("Package manager has died", e);
1957 }
1958 }
1959
1960 @Override
1961 public int getUidForSharedUser(String sharedUserName)
1962 throws NameNotFoundException {
1963 try {
1964 int uid = mPM.getUidForSharedUser(sharedUserName);
1965 if(uid != -1) {
1966 return uid;
1967 }
1968 } catch (RemoteException e) {
1969 throw new RuntimeException("Package manager has died", e);
1970 }
1971 throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
1972 }
1973
1974 @Override
1975 public List<PackageInfo> getInstalledPackages(int flags) {
1976 try {
1977 return mPM.getInstalledPackages(flags);
1978 } catch (RemoteException e) {
1979 throw new RuntimeException("Package manager has died", e);
1980 }
1981 }
1982
1983 @Override
1984 public List<ApplicationInfo> getInstalledApplications(int flags) {
1985 try {
1986 return mPM.getInstalledApplications(flags);
1987 } catch (RemoteException e) {
1988 throw new RuntimeException("Package manager has died", e);
1989 }
1990 }
1991
1992 @Override
1993 public ResolveInfo resolveActivity(Intent intent, int flags) {
1994 try {
1995 return mPM.resolveIntent(
1996 intent,
1997 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
1998 flags);
1999 } catch (RemoteException e) {
2000 throw new RuntimeException("Package manager has died", e);
2001 }
2002 }
2003
2004 @Override
2005 public List<ResolveInfo> queryIntentActivities(Intent intent,
2006 int flags) {
2007 try {
2008 return mPM.queryIntentActivities(
2009 intent,
2010 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2011 flags);
2012 } catch (RemoteException e) {
2013 throw new RuntimeException("Package manager has died", e);
2014 }
2015 }
2016
2017 @Override
2018 public List<ResolveInfo> queryIntentActivityOptions(
2019 ComponentName caller, Intent[] specifics, Intent intent,
2020 int flags) {
2021 final ContentResolver resolver = mContext.getContentResolver();
2022
2023 String[] specificTypes = null;
2024 if (specifics != null) {
2025 final int N = specifics.length;
2026 for (int i=0; i<N; i++) {
2027 Intent sp = specifics[i];
2028 if (sp != null) {
2029 String t = sp.resolveTypeIfNeeded(resolver);
2030 if (t != null) {
2031 if (specificTypes == null) {
2032 specificTypes = new String[N];
2033 }
2034 specificTypes[i] = t;
2035 }
2036 }
2037 }
2038 }
2039
2040 try {
2041 return mPM.queryIntentActivityOptions(caller, specifics,
2042 specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
2043 flags);
2044 } catch (RemoteException e) {
2045 throw new RuntimeException("Package manager has died", e);
2046 }
2047 }
2048
2049 @Override
2050 public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
2051 try {
2052 return mPM.queryIntentReceivers(
2053 intent,
2054 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2055 flags);
2056 } catch (RemoteException e) {
2057 throw new RuntimeException("Package manager has died", e);
2058 }
2059 }
2060
2061 @Override
2062 public ResolveInfo resolveService(Intent intent, int flags) {
2063 try {
2064 return mPM.resolveService(
2065 intent,
2066 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2067 flags);
2068 } catch (RemoteException e) {
2069 throw new RuntimeException("Package manager has died", e);
2070 }
2071 }
2072
2073 @Override
2074 public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
2075 try {
2076 return mPM.queryIntentServices(
2077 intent,
2078 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2079 flags);
2080 } catch (RemoteException e) {
2081 throw new RuntimeException("Package manager has died", e);
2082 }
2083 }
2084
2085 @Override
2086 public ProviderInfo resolveContentProvider(String name,
2087 int flags) {
2088 try {
2089 return mPM.resolveContentProvider(name, flags);
2090 } catch (RemoteException e) {
2091 throw new RuntimeException("Package manager has died", e);
2092 }
2093 }
2094
2095 @Override
2096 public List<ProviderInfo> queryContentProviders(String processName,
2097 int uid, int flags) {
2098 try {
2099 return mPM.queryContentProviders(processName, uid, flags);
2100 } catch (RemoteException e) {
2101 throw new RuntimeException("Package manager has died", e);
2102 }
2103 }
2104
2105 @Override
2106 public InstrumentationInfo getInstrumentationInfo(
2107 ComponentName className, int flags)
2108 throws NameNotFoundException {
2109 try {
2110 InstrumentationInfo ii = mPM.getInstrumentationInfo(
2111 className, flags);
2112 if (ii != null) {
2113 return ii;
2114 }
2115 } catch (RemoteException e) {
2116 throw new RuntimeException("Package manager has died", e);
2117 }
2118
2119 throw new NameNotFoundException(className.toString());
2120 }
2121
2122 @Override
2123 public List<InstrumentationInfo> queryInstrumentation(
2124 String targetPackage, int flags) {
2125 try {
2126 return mPM.queryInstrumentation(targetPackage, flags);
2127 } catch (RemoteException e) {
2128 throw new RuntimeException("Package manager has died", e);
2129 }
2130 }
2131
2132 @Override public Drawable getDrawable(String packageName, int resid,
2133 ApplicationInfo appInfo) {
2134 ResourceName name = new ResourceName(packageName, resid);
2135 Drawable dr = getCachedIcon(name);
2136 if (dr != null) {
2137 return dr;
2138 }
2139 if (appInfo == null) {
2140 try {
2141 appInfo = getApplicationInfo(packageName, 0);
2142 } catch (NameNotFoundException e) {
2143 return null;
2144 }
2145 }
2146 try {
2147 Resources r = getResourcesForApplication(appInfo);
2148 dr = r.getDrawable(resid);
Dianne Hackborn11ea3342009-07-22 21:48:55 -07002149 if (false) {
2150 RuntimeException e = new RuntimeException("here");
2151 e.fillInStackTrace();
2152 Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
2153 + " from package " + packageName
2154 + ": app scale=" + r.getCompatibilityInfo().applicationScale
2155 + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
2156 e);
2157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
2159 + Integer.toHexString(resid) + " from " + r
2160 + ": " + dr);
2161 putCachedIcon(name, dr);
2162 return dr;
2163 } catch (NameNotFoundException e) {
2164 Log.w("PackageManager", "Failure retrieving resources for"
2165 + appInfo.packageName);
2166 } catch (RuntimeException e) {
2167 // If an exception was thrown, fall through to return
2168 // default icon.
2169 Log.w("PackageManager", "Failure retrieving icon 0x"
2170 + Integer.toHexString(resid) + " in package "
2171 + packageName, e);
2172 }
2173 return null;
2174 }
2175
2176 @Override public Drawable getActivityIcon(ComponentName activityName)
2177 throws NameNotFoundException {
2178 return getActivityInfo(activityName, 0).loadIcon(this);
2179 }
2180
2181 @Override public Drawable getActivityIcon(Intent intent)
2182 throws NameNotFoundException {
2183 if (intent.getComponent() != null) {
2184 return getActivityIcon(intent.getComponent());
2185 }
2186
2187 ResolveInfo info = resolveActivity(
2188 intent, PackageManager.MATCH_DEFAULT_ONLY);
2189 if (info != null) {
2190 return info.activityInfo.loadIcon(this);
2191 }
2192
2193 throw new NameNotFoundException(intent.toURI());
2194 }
2195
2196 @Override public Drawable getDefaultActivityIcon() {
2197 return Resources.getSystem().getDrawable(
2198 com.android.internal.R.drawable.sym_def_app_icon);
2199 }
2200
2201 @Override public Drawable getApplicationIcon(ApplicationInfo info) {
Jeff Brown07330792010-03-30 19:57:08 -07002202 return info.loadIcon(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 }
2204
2205 @Override public Drawable getApplicationIcon(String packageName)
2206 throws NameNotFoundException {
2207 return getApplicationIcon(getApplicationInfo(packageName, 0));
2208 }
Adam Powell81cd2e92010-04-21 16:35:18 -07002209
2210 @Override
2211 public Drawable getActivityLogo(ComponentName activityName)
2212 throws NameNotFoundException {
2213 return getActivityInfo(activityName, 0).loadLogo(this);
2214 }
2215
2216 @Override
2217 public Drawable getActivityLogo(Intent intent)
2218 throws NameNotFoundException {
2219 if (intent.getComponent() != null) {
2220 return getActivityLogo(intent.getComponent());
2221 }
2222
2223 ResolveInfo info = resolveActivity(
2224 intent, PackageManager.MATCH_DEFAULT_ONLY);
2225 if (info != null) {
2226 return info.activityInfo.loadLogo(this);
2227 }
2228
2229 throw new NameNotFoundException(intent.toUri(0));
2230 }
2231
2232 @Override
2233 public Drawable getApplicationLogo(ApplicationInfo info) {
2234 return info.loadLogo(this);
2235 }
2236
2237 @Override
2238 public Drawable getApplicationLogo(String packageName)
2239 throws NameNotFoundException {
2240 return getApplicationLogo(getApplicationInfo(packageName, 0));
2241 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242
2243 @Override public Resources getResourcesForActivity(
2244 ComponentName activityName) throws NameNotFoundException {
2245 return getResourcesForApplication(
2246 getActivityInfo(activityName, 0).applicationInfo);
2247 }
2248
2249 @Override public Resources getResourcesForApplication(
2250 ApplicationInfo app) throws NameNotFoundException {
2251 if (app.packageName.equals("system")) {
2252 return mContext.mMainThread.getSystemContext().getResources();
2253 }
2254 Resources r = mContext.mMainThread.getTopLevelResources(
2255 app.uid == Process.myUid() ? app.sourceDir
Dianne Hackborn11ea3342009-07-22 21:48:55 -07002256 : app.publicSourceDir, mContext.mPackageInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002257 if (r != null) {
2258 return r;
2259 }
2260 throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
2261 }
2262
2263 @Override public Resources getResourcesForApplication(
2264 String appPackageName) throws NameNotFoundException {
2265 return getResourcesForApplication(
2266 getApplicationInfo(appPackageName, 0));
2267 }
2268
2269 int mCachedSafeMode = -1;
2270 @Override public boolean isSafeMode() {
2271 try {
2272 if (mCachedSafeMode < 0) {
2273 mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
2274 }
2275 return mCachedSafeMode != 0;
2276 } catch (RemoteException e) {
2277 throw new RuntimeException("Package manager has died", e);
2278 }
2279 }
2280
2281 static void configurationChanged() {
2282 synchronized (sSync) {
2283 sIconCache.clear();
2284 sStringCache.clear();
2285 }
2286 }
2287
Dianne Hackborn21556372010-02-04 16:34:40 -08002288 ApplicationPackageManager(ContextImpl context,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 IPackageManager pm) {
2290 mContext = context;
2291 mPM = pm;
2292 }
2293
2294 private Drawable getCachedIcon(ResourceName name) {
2295 synchronized (sSync) {
2296 WeakReference<Drawable> wr = sIconCache.get(name);
2297 if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
2298 + name + ": " + wr);
2299 if (wr != null) { // we have the activity
2300 Drawable dr = wr.get();
2301 if (dr != null) {
2302 if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
2303 + name + ": " + dr);
2304 return dr;
2305 }
2306 // our entry has been purged
2307 sIconCache.remove(name);
2308 }
2309 }
2310 return null;
2311 }
2312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002313 private void putCachedIcon(ResourceName name, Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002314 synchronized (sSync) {
2315 sIconCache.put(name, new WeakReference<Drawable>(dr));
2316 if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
2317 + name + ": " + dr);
2318 }
2319 }
2320
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002321 static final void handlePackageBroadcast(int cmd, String[] pkgList,
2322 boolean hasPkgInfo) {
2323 boolean immediateGc = false;
2324 if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
2325 immediateGc = true;
2326 }
2327 if (pkgList != null && (pkgList.length > 0)) {
2328 boolean needCleanup = false;
2329 for (String ssp : pkgList) {
2330 synchronized (sSync) {
2331 if (sIconCache.size() > 0) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002332 Iterator<ResourceName> it = sIconCache.keySet().iterator();
2333 while (it.hasNext()) {
2334 ResourceName nm = it.next();
2335 if (nm.packageName.equals(ssp)) {
2336 //Log.i(TAG, "Removing cached drawable for " + nm);
2337 it.remove();
2338 needCleanup = true;
2339 }
2340 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002341 }
2342 if (sStringCache.size() > 0) {
2343 Iterator<ResourceName> it = sStringCache.keySet().iterator();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002344 while (it.hasNext()) {
2345 ResourceName nm = it.next();
2346 if (nm.packageName.equals(ssp)) {
2347 //Log.i(TAG, "Removing cached string for " + nm);
2348 it.remove();
2349 needCleanup = true;
2350 }
2351 }
2352 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002353 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002354 }
2355 if (needCleanup || hasPkgInfo) {
2356 if (immediateGc) {
2357 // Schedule an immediate gc.
2358 Runtime.getRuntime().gc();
2359 } else {
2360 ActivityThread.currentActivityThread().scheduleGcIdler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 }
2362 }
2363 }
2364 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 private static final class ResourceName {
2367 final String packageName;
2368 final int iconId;
2369
2370 ResourceName(String _packageName, int _iconId) {
2371 packageName = _packageName;
2372 iconId = _iconId;
2373 }
2374
2375 ResourceName(ApplicationInfo aInfo, int _iconId) {
2376 this(aInfo.packageName, _iconId);
2377 }
2378
2379 ResourceName(ComponentInfo cInfo, int _iconId) {
2380 this(cInfo.applicationInfo.packageName, _iconId);
2381 }
2382
2383 ResourceName(ResolveInfo rInfo, int _iconId) {
2384 this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
2385 }
2386
2387 @Override
2388 public boolean equals(Object o) {
2389 if (this == o) return true;
2390 if (o == null || getClass() != o.getClass()) return false;
2391
2392 ResourceName that = (ResourceName) o;
2393
2394 if (iconId != that.iconId) return false;
2395 return !(packageName != null ?
2396 !packageName.equals(that.packageName) : that.packageName != null);
2397
2398 }
2399
2400 @Override
2401 public int hashCode() {
2402 int result;
2403 result = packageName.hashCode();
2404 result = 31 * result + iconId;
2405 return result;
2406 }
2407
2408 @Override
2409 public String toString() {
2410 return "{ResourceName " + packageName + " / " + iconId + "}";
2411 }
2412 }
2413
2414 private CharSequence getCachedString(ResourceName name) {
2415 synchronized (sSync) {
2416 WeakReference<CharSequence> wr = sStringCache.get(name);
2417 if (wr != null) { // we have the activity
2418 CharSequence cs = wr.get();
2419 if (cs != null) {
2420 return cs;
2421 }
2422 // our entry has been purged
2423 sStringCache.remove(name);
2424 }
2425 }
2426 return null;
2427 }
2428
2429 private void putCachedString(ResourceName name, CharSequence cs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 synchronized (sSync) {
2431 sStringCache.put(name, new WeakReference<CharSequence>(cs));
2432 }
2433 }
2434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002435 @Override
2436 public CharSequence getText(String packageName, int resid,
2437 ApplicationInfo appInfo) {
2438 ResourceName name = new ResourceName(packageName, resid);
2439 CharSequence text = getCachedString(name);
2440 if (text != null) {
2441 return text;
2442 }
2443 if (appInfo == null) {
2444 try {
2445 appInfo = getApplicationInfo(packageName, 0);
2446 } catch (NameNotFoundException e) {
2447 return null;
2448 }
2449 }
2450 try {
2451 Resources r = getResourcesForApplication(appInfo);
2452 text = r.getText(resid);
2453 putCachedString(name, text);
2454 return text;
2455 } catch (NameNotFoundException e) {
2456 Log.w("PackageManager", "Failure retrieving resources for"
2457 + appInfo.packageName);
2458 } catch (RuntimeException e) {
2459 // If an exception was thrown, fall through to return
2460 // default icon.
2461 Log.w("PackageManager", "Failure retrieving text 0x"
2462 + Integer.toHexString(resid) + " in package "
2463 + packageName, e);
2464 }
2465 return null;
2466 }
2467
2468 @Override
2469 public XmlResourceParser getXml(String packageName, int resid,
2470 ApplicationInfo appInfo) {
2471 if (appInfo == null) {
2472 try {
2473 appInfo = getApplicationInfo(packageName, 0);
2474 } catch (NameNotFoundException e) {
2475 return null;
2476 }
2477 }
2478 try {
2479 Resources r = getResourcesForApplication(appInfo);
2480 return r.getXml(resid);
2481 } catch (RuntimeException e) {
2482 // If an exception was thrown, fall through to return
2483 // default icon.
2484 Log.w("PackageManager", "Failure retrieving xml 0x"
2485 + Integer.toHexString(resid) + " in package "
2486 + packageName, e);
2487 } catch (NameNotFoundException e) {
2488 Log.w("PackageManager", "Failure retrieving resources for"
2489 + appInfo.packageName);
2490 }
2491 return null;
2492 }
2493
2494 @Override
2495 public CharSequence getApplicationLabel(ApplicationInfo info) {
Jeff Brown07330792010-03-30 19:57:08 -07002496 return info.loadLabel(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002497 }
2498
2499 @Override
Jacek Surazski65e13172009-04-28 15:26:38 +02002500 public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
2501 String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002502 try {
Jacek Surazski65e13172009-04-28 15:26:38 +02002503 mPM.installPackage(packageURI, observer, flags, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 } catch (RemoteException e) {
2505 // Should never happen!
2506 }
2507 }
2508
2509 @Override
Suchi Amalapurapu8946dd32010-02-19 09:19:34 -08002510 public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
2511 try {
2512 mPM.movePackage(packageName, observer, flags);
2513 } catch (RemoteException e) {
2514 // Should never happen!
2515 }
2516 }
2517
2518 @Override
Jacek Surazski65e13172009-04-28 15:26:38 +02002519 public String getInstallerPackageName(String packageName) {
2520 try {
2521 return mPM.getInstallerPackageName(packageName);
2522 } catch (RemoteException e) {
2523 // Should never happen!
2524 }
2525 return null;
2526 }
2527
2528 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
2530 try {
2531 mPM.deletePackage(packageName, observer, flags);
2532 } catch (RemoteException e) {
2533 // Should never happen!
2534 }
2535 }
2536 @Override
2537 public void clearApplicationUserData(String packageName,
2538 IPackageDataObserver observer) {
2539 try {
2540 mPM.clearApplicationUserData(packageName, observer);
2541 } catch (RemoteException e) {
2542 // Should never happen!
2543 }
2544 }
2545 @Override
2546 public void deleteApplicationCacheFiles(String packageName,
2547 IPackageDataObserver observer) {
2548 try {
2549 mPM.deleteApplicationCacheFiles(packageName, observer);
2550 } catch (RemoteException e) {
2551 // Should never happen!
2552 }
2553 }
2554 @Override
2555 public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
2556 try {
2557 mPM.freeStorageAndNotify(idealStorageSize, observer);
2558 } catch (RemoteException e) {
2559 // Should never happen!
2560 }
2561 }
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -07002562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002563 @Override
Suchi Amalapurapubc806f62009-06-17 15:18:19 -07002564 public void freeStorage(long freeStorageSize, IntentSender pi) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 try {
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -07002566 mPM.freeStorage(freeStorageSize, pi);
2567 } catch (RemoteException e) {
2568 // Should never happen!
2569 }
2570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571
2572 @Override
2573 public void getPackageSizeInfo(String packageName,
2574 IPackageStatsObserver observer) {
2575 try {
2576 mPM.getPackageSizeInfo(packageName, observer);
2577 } catch (RemoteException e) {
2578 // Should never happen!
2579 }
2580 }
2581 @Override
2582 public void addPackageToPreferred(String packageName) {
2583 try {
2584 mPM.addPackageToPreferred(packageName);
2585 } catch (RemoteException e) {
2586 // Should never happen!
2587 }
2588 }
2589
2590 @Override
2591 public void removePackageFromPreferred(String packageName) {
2592 try {
2593 mPM.removePackageFromPreferred(packageName);
2594 } catch (RemoteException e) {
2595 // Should never happen!
2596 }
2597 }
2598
2599 @Override
2600 public List<PackageInfo> getPreferredPackages(int flags) {
2601 try {
2602 return mPM.getPreferredPackages(flags);
2603 } catch (RemoteException e) {
2604 // Should never happen!
2605 }
2606 return new ArrayList<PackageInfo>();
2607 }
2608
2609 @Override
2610 public void addPreferredActivity(IntentFilter filter,
2611 int match, ComponentName[] set, ComponentName activity) {
2612 try {
2613 mPM.addPreferredActivity(filter, match, set, activity);
2614 } catch (RemoteException e) {
2615 // Should never happen!
2616 }
2617 }
2618
2619 @Override
Satish Sampath8dbe6122009-06-02 23:35:54 +01002620 public void replacePreferredActivity(IntentFilter filter,
2621 int match, ComponentName[] set, ComponentName activity) {
2622 try {
2623 mPM.replacePreferredActivity(filter, match, set, activity);
2624 } catch (RemoteException e) {
2625 // Should never happen!
2626 }
2627 }
2628
2629 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002630 public void clearPackagePreferredActivities(String packageName) {
2631 try {
2632 mPM.clearPackagePreferredActivities(packageName);
2633 } catch (RemoteException e) {
2634 // Should never happen!
2635 }
2636 }
2637
2638 @Override
2639 public int getPreferredActivities(List<IntentFilter> outFilters,
2640 List<ComponentName> outActivities, String packageName) {
2641 try {
2642 return mPM.getPreferredActivities(outFilters, outActivities, packageName);
2643 } catch (RemoteException e) {
2644 // Should never happen!
2645 }
2646 return 0;
2647 }
2648
2649 @Override
2650 public void setComponentEnabledSetting(ComponentName componentName,
2651 int newState, int flags) {
2652 try {
2653 mPM.setComponentEnabledSetting(componentName, newState, flags);
2654 } catch (RemoteException e) {
2655 // Should never happen!
2656 }
2657 }
2658
2659 @Override
2660 public int getComponentEnabledSetting(ComponentName componentName) {
2661 try {
2662 return mPM.getComponentEnabledSetting(componentName);
2663 } catch (RemoteException e) {
2664 // Should never happen!
2665 }
2666 return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2667 }
2668
2669 @Override
2670 public void setApplicationEnabledSetting(String packageName,
2671 int newState, int flags) {
2672 try {
2673 mPM.setApplicationEnabledSetting(packageName, newState, flags);
2674 } catch (RemoteException e) {
2675 // Should never happen!
2676 }
2677 }
2678
2679 @Override
2680 public int getApplicationEnabledSetting(String packageName) {
2681 try {
2682 return mPM.getApplicationEnabledSetting(packageName);
2683 } catch (RemoteException e) {
2684 // Should never happen!
2685 }
2686 return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2687 }
2688
Kenny Root93565c42010-06-18 15:46:06 -07002689 @Override
2690 public void setPackageObbPath(String packageName, String path) {
2691 try {
2692 mPM.setPackageObbPath(packageName, path);
2693 } catch (RemoteException e) {
2694 // Should never happen!
2695 }
2696 }
2697
Dianne Hackborn21556372010-02-04 16:34:40 -08002698 private final ContextImpl mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002699 private final IPackageManager mPM;
2700
2701 private static final Object sSync = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
2703 = new HashMap<ResourceName, WeakReference<Drawable> >();
2704 private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
2705 = new HashMap<ResourceName, WeakReference<CharSequence> >();
2706 }
2707
2708 // ----------------------------------------------------------------------
2709 // ----------------------------------------------------------------------
2710 // ----------------------------------------------------------------------
2711
2712 private static final class SharedPreferencesImpl implements SharedPreferences {
2713
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002714 // Lock ordering rules:
2715 // - acquire SharedPreferencesImpl.this before EditorImpl.this
2716 // - acquire mWritingToDiskLock before EditorImpl.this
2717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002718 private final File mFile;
2719 private final File mBackupFile;
2720 private final int mMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002721
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002722 private Map<String, Object> mMap; // guarded by 'this'
2723 private long mTimestamp; // guarded by 'this'
2724 private int mDiskWritesInFlight = 0; // guarded by 'this'
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002725 private boolean mLoaded = false; // guarded by 'this'
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002726
2727 private final Object mWritingToDiskLock = new Object();
The Android Open Source Project10592532009-03-18 17:39:46 -07002728 private static final Object mContent = new Object();
2729 private WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730
2731 SharedPreferencesImpl(
2732 File file, int mode, Map initialContents) {
2733 mFile = file;
2734 mBackupFile = makeBackupFile(file);
2735 mMode = mode;
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002736 mLoaded = initialContents != null;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002737 mMap = initialContents != null ? initialContents : new HashMap<String, Object>();
2738 FileStatus stat = new FileStatus();
2739 if (FileUtils.getFileStatus(file.getPath(), stat)) {
2740 mTimestamp = stat.mtime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002742 mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002743 }
2744
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002745 // Has this SharedPreferences ever had values assigned to it?
2746 boolean isLoaded() {
2747 synchronized (this) {
2748 return mLoaded;
2749 }
2750 }
2751
2752 // Has the file changed out from under us? i.e. writes that
2753 // we didn't instigate.
2754 public boolean hasFileChangedUnexpectedly() {
2755 synchronized (this) {
2756 if (mDiskWritesInFlight > 0) {
2757 // If we know we caused it, it's not unexpected.
2758 Log.d(TAG, "disk write in flight, not unexpected.");
2759 return false;
2760 }
2761 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002762 FileStatus stat = new FileStatus();
2763 if (!FileUtils.getFileStatus(mFile.getPath(), stat)) {
2764 return true;
2765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002766 synchronized (this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002767 return mTimestamp != stat.mtime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002768 }
2769 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002771 public void replace(Map newContents) {
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002772 synchronized (this) {
2773 mLoaded = true;
2774 if (newContents != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 mMap = newContents;
2776 }
2777 }
2778 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002780 public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2781 synchronized(this) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002782 mListeners.put(listener, mContent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 }
2784 }
2785
2786 public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2787 synchronized(this) {
2788 mListeners.remove(listener);
2789 }
2790 }
2791
2792 public Map<String, ?> getAll() {
2793 synchronized(this) {
2794 //noinspection unchecked
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002795 return new HashMap<String, Object>(mMap);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 }
2797 }
2798
2799 public String getString(String key, String defValue) {
2800 synchronized (this) {
2801 String v = (String)mMap.get(key);
2802 return v != null ? v : defValue;
2803 }
2804 }
2805
2806 public int getInt(String key, int defValue) {
2807 synchronized (this) {
2808 Integer v = (Integer)mMap.get(key);
2809 return v != null ? v : defValue;
2810 }
2811 }
2812 public long getLong(String key, long defValue) {
2813 synchronized (this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002814 Long v = (Long)mMap.get(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002815 return v != null ? v : defValue;
2816 }
2817 }
2818 public float getFloat(String key, float defValue) {
2819 synchronized (this) {
2820 Float v = (Float)mMap.get(key);
2821 return v != null ? v : defValue;
2822 }
2823 }
2824 public boolean getBoolean(String key, boolean defValue) {
2825 synchronized (this) {
2826 Boolean v = (Boolean)mMap.get(key);
2827 return v != null ? v : defValue;
2828 }
2829 }
2830
2831 public boolean contains(String key) {
2832 synchronized (this) {
2833 return mMap.containsKey(key);
2834 }
2835 }
2836
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002837 public Editor edit() {
2838 return new EditorImpl();
2839 }
2840
2841 // Return value from EditorImpl#commitToMemory()
2842 private static class MemoryCommitResult {
2843 public boolean changesMade; // any keys different?
2844 public List<String> keysModified; // may be null
2845 public Set<OnSharedPreferenceChangeListener> listeners; // may be null
2846 public Map<?, ?> mapToWriteToDisk;
2847 public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
2848 public volatile boolean writeToDiskResult = false;
2849
2850 public void setDiskWriteResult(boolean result) {
2851 writeToDiskResult = result;
2852 writtenToDiskLatch.countDown();
2853 }
2854 }
2855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002856 public final class EditorImpl implements Editor {
2857 private final Map<String, Object> mModified = Maps.newHashMap();
2858 private boolean mClear = false;
2859
2860 public Editor putString(String key, String value) {
2861 synchronized (this) {
2862 mModified.put(key, value);
2863 return this;
2864 }
2865 }
2866 public Editor putInt(String key, int value) {
2867 synchronized (this) {
2868 mModified.put(key, value);
2869 return this;
2870 }
2871 }
2872 public Editor putLong(String key, long value) {
2873 synchronized (this) {
2874 mModified.put(key, value);
2875 return this;
2876 }
2877 }
2878 public Editor putFloat(String key, float value) {
2879 synchronized (this) {
2880 mModified.put(key, value);
2881 return this;
2882 }
2883 }
2884 public Editor putBoolean(String key, boolean value) {
2885 synchronized (this) {
2886 mModified.put(key, value);
2887 return this;
2888 }
2889 }
2890
2891 public Editor remove(String key) {
2892 synchronized (this) {
2893 mModified.put(key, this);
2894 return this;
2895 }
2896 }
2897
2898 public Editor clear() {
2899 synchronized (this) {
2900 mClear = true;
2901 return this;
2902 }
2903 }
2904
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07002905 public void apply() {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002906 final MemoryCommitResult mcr = commitToMemory();
2907 final Runnable awaitCommit = new Runnable() {
2908 public void run() {
2909 try {
2910 mcr.writtenToDiskLatch.await();
2911 } catch (InterruptedException ignored) {
2912 }
2913 }
2914 };
2915
2916 QueuedWork.add(awaitCommit);
2917
2918 Runnable postWriteRunnable = new Runnable() {
2919 public void run() {
2920 awaitCommit.run();
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002921 QueuedWork.remove(awaitCommit);
2922 }
2923 };
2924
2925 SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
2926
2927 // Okay to notify the listeners before it's hit disk
2928 // because the listeners should always get the same
2929 // SharedPreferences instance back, which has the
2930 // changes reflected in memory.
2931 notifyListeners(mcr);
Brad Fitzpatrickedf32d02010-08-25 13:13:36 -07002932 }
2933
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002934 // Returns true if any changes were made
2935 private MemoryCommitResult commitToMemory() {
2936 MemoryCommitResult mcr = new MemoryCommitResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002937 synchronized (SharedPreferencesImpl.this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002938 // We optimistically don't make a deep copy until
2939 // a memory commit comes in when we're already
2940 // writing to disk.
2941 if (mDiskWritesInFlight > 0) {
2942 // We can't modify our mMap as a currently
2943 // in-flight write owns it. Clone it before
2944 // modifying it.
2945 // noinspection unchecked
2946 mMap = new HashMap<String, Object>(mMap);
2947 }
2948 mcr.mapToWriteToDisk = mMap;
2949 mDiskWritesInFlight++;
2950
2951 boolean hasListeners = mListeners.size() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952 if (hasListeners) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002953 mcr.keysModified = new ArrayList<String>();
2954 mcr.listeners =
2955 new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002956 }
2957
2958 synchronized (this) {
2959 if (mClear) {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002960 if (!mMap.isEmpty()) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002961 mcr.changesMade = true;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002962 mMap.clear();
2963 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 mClear = false;
2965 }
2966
The Android Open Source Project10592532009-03-18 17:39:46 -07002967 for (Entry<String, Object> e : mModified.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 String k = e.getKey();
2969 Object v = e.getValue();
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002970 if (v == this) { // magic value for a removal mutation
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002971 if (!mMap.containsKey(k)) {
2972 continue;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002973 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002974 mMap.remove(k);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 } else {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002976 boolean isSame = false;
2977 if (mMap.containsKey(k)) {
2978 Object existingValue = mMap.get(k);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002979 if (existingValue != null && existingValue.equals(v)) {
2980 continue;
2981 }
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002982 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002983 mMap.put(k, v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002984 }
2985
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002986 mcr.changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002987 if (hasListeners) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002988 mcr.keysModified.add(k);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002989 }
2990 }
2991
2992 mModified.clear();
2993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002994 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002995 return mcr;
2996 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002998 public boolean commit() {
2999 MemoryCommitResult mcr = commitToMemory();
3000 SharedPreferencesImpl.this.enqueueDiskWrite(
3001 mcr, null /* sync write on this thread okay */);
3002 try {
3003 mcr.writtenToDiskLatch.await();
3004 } catch (InterruptedException e) {
3005 return false;
3006 }
3007 notifyListeners(mcr);
3008 return mcr.writeToDiskResult;
3009 }
3010
3011 private void notifyListeners(final MemoryCommitResult mcr) {
3012 if (mcr.listeners == null || mcr.keysModified == null ||
3013 mcr.keysModified.size() == 0) {
3014 return;
3015 }
3016 if (Looper.myLooper() == Looper.getMainLooper()) {
3017 for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
3018 final String key = mcr.keysModified.get(i);
3019 for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
The Android Open Source Project10592532009-03-18 17:39:46 -07003020 if (listener != null) {
3021 listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
3022 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003023 }
3024 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003025 } else {
3026 // Run this function on the main thread.
3027 ActivityThread.sMainThreadHandler.post(new Runnable() {
3028 public void run() {
3029 notifyListeners(mcr);
3030 }
3031 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003033 }
3034 }
3035
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003036 /**
3037 * Enqueue an already-committed-to-memory result to be written
3038 * to disk.
3039 *
3040 * They will be written to disk one-at-a-time in the order
3041 * that they're enqueued.
3042 *
3043 * @param postWriteRunnable if non-null, we're being called
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07003044 * from apply() and this is the runnable to run after
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003045 * the write proceeds. if null (from a regular commit()),
3046 * then we're allowed to do this disk write on the main
3047 * thread (which in addition to reducing allocations and
3048 * creating a background thread, this has the advantage that
3049 * we catch them in userdebug StrictMode reports to convert
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07003050 * them where possible to apply() ...)
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003051 */
3052 private void enqueueDiskWrite(final MemoryCommitResult mcr,
3053 final Runnable postWriteRunnable) {
3054 final Runnable writeToDiskRunnable = new Runnable() {
3055 public void run() {
3056 synchronized (mWritingToDiskLock) {
3057 writeToFile(mcr);
3058 }
3059 synchronized (SharedPreferencesImpl.this) {
3060 mDiskWritesInFlight--;
3061 }
3062 if (postWriteRunnable != null) {
3063 postWriteRunnable.run();
3064 }
3065 }
3066 };
3067
3068 final boolean isFromSyncCommit = (postWriteRunnable == null);
3069
3070 // Typical #commit() path with fewer allocations, doing a write on
3071 // the current thread.
3072 if (isFromSyncCommit) {
3073 boolean wasEmpty = false;
3074 synchronized (SharedPreferencesImpl.this) {
3075 wasEmpty = mDiskWritesInFlight == 1;
3076 }
3077 if (wasEmpty) {
3078 writeToDiskRunnable.run();
3079 return;
3080 }
3081 }
3082
3083 QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003084 }
Brad Fitzpatrickedf32d02010-08-25 13:13:36 -07003085
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003086 private static FileOutputStream createFileOutputStream(File file) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003087 FileOutputStream str = null;
3088 try {
3089 str = new FileOutputStream(file);
3090 } catch (FileNotFoundException e) {
3091 File parent = file.getParentFile();
3092 if (!parent.mkdir()) {
3093 Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
3094 return null;
3095 }
3096 FileUtils.setPermissions(
3097 parent.getPath(),
3098 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
3099 -1, -1);
3100 try {
3101 str = new FileOutputStream(file);
3102 } catch (FileNotFoundException e2) {
3103 Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
3104 }
3105 }
3106 return str;
3107 }
3108
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003109 // Note: must hold mWritingToDiskLock
3110 private void writeToFile(MemoryCommitResult mcr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003111 // Rename the current file so it may be used as a backup during the next read
3112 if (mFile.exists()) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003113 if (!mcr.changesMade) {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003114 // If the file already exists, but no changes were
3115 // made to the underlying map, it's wasteful to
3116 // re-write the file. Return as if we wrote it
3117 // out.
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003118 mcr.setDiskWriteResult(true);
3119 return;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003120 }
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07003121 if (!mBackupFile.exists()) {
3122 if (!mFile.renameTo(mBackupFile)) {
3123 Log.e(TAG, "Couldn't rename file " + mFile
3124 + " to backup file " + mBackupFile);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003125 mcr.setDiskWriteResult(false);
3126 return;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07003127 }
3128 } else {
3129 mFile.delete();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 }
3131 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003133 // Attempt to write the file, delete the backup and return true as atomically as
3134 // possible. If any exception occurs, delete the new file; next time we will restore
3135 // from the backup.
3136 try {
3137 FileOutputStream str = createFileOutputStream(mFile);
3138 if (str == null) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003139 mcr.setDiskWriteResult(false);
3140 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003142 XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 str.close();
3144 setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003145 FileStatus stat = new FileStatus();
3146 if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
3147 synchronized (this) {
3148 mTimestamp = stat.mtime;
3149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 }
Dianne Hackborn51bf0772009-03-24 19:11:41 -07003151 // Writing was successful, delete the backup file if there is one.
3152 mBackupFile.delete();
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003153 mcr.setDiskWriteResult(true);
3154 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003155 } catch (XmlPullParserException e) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003156 Log.w(TAG, "writeToFile: Got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 } catch (IOException e) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003158 Log.w(TAG, "writeToFile: Got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 }
3160 // Clean up an unsuccessfully written file
3161 if (mFile.exists()) {
3162 if (!mFile.delete()) {
3163 Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
3164 }
3165 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003166 mcr.setDiskWriteResult(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 }
3168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003169}