blob: 5afea137f6e7016a7bcd46134d138f456a79d9e2 [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;
56import android.content.res.AssetManager;
57import android.content.res.Resources;
58import android.content.res.XmlResourceParser;
Vasu Nori74f170f2010-06-01 18:06:18 -070059import android.database.DatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import 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;
Bai Taoa58a8752010-07-13 15:32:16 +080065import android.location.CountryDetector;
66import android.location.ICountryDetector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.location.ILocationManager;
68import android.location.LocationManager;
69import android.media.AudioManager;
70import android.net.ConnectivityManager;
71import android.net.IConnectivityManager;
Steve Howarda2709362010-07-02 17:12:48 -070072import android.net.DownloadManager;
Irfan Sheriffc9b68512010-04-08 14:12:33 -070073import android.net.ThrottleManager;
74import android.net.IThrottleManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import android.net.Uri;
76import android.net.wifi.IWifiManager;
77import android.net.wifi.WifiManager;
78import android.os.Binder;
Adam Powellc63806d2010-09-23 16:21:30 -070079import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.Bundle;
Dan Egnorf18a01c2009-11-12 11:32:50 -080081import android.os.DropBoxManager;
Oscar Montemayor539d3c42010-01-29 15:27:00 -080082import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.os.FileUtils;
84import android.os.Handler;
85import android.os.IBinder;
86import android.os.IPowerManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070087import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.os.PowerManager;
89import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070090import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.os.ServiceManager;
92import android.os.Vibrator;
93import android.os.FileUtils.FileStatus;
San Mehatb1043402010-02-05 08:26:50 -080094import android.os.storage.StorageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.telephony.TelephonyManager;
Dianne Hackborn9f531192010-08-04 17:48:03 -070096import android.content.ClipboardManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.util.AndroidRuntimeException;
98import android.util.Log;
99import android.view.ContextThemeWrapper;
100import android.view.LayoutInflater;
101import android.view.WindowManagerImpl;
svetoslavganov75986cf2009-05-14 22:28:01 -0700102import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import android.view.inputmethod.InputMethodManager;
Fred Quintana60307342009-03-24 22:48:12 -0700104import android.accounts.AccountManager;
105import android.accounts.IAccountManager;
Dianne Hackborn87bba1e2010-02-26 17:25:54 -0800106import android.app.admin.DevicePolicyManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107
Dan Egnorf18a01c2009-11-12 11:32:50 -0800108import com.android.internal.os.IDropBoxManagerService;
Dan Egnor95240272009-10-27 18:23:39 -0700109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileInputStream;
112import java.io.FileNotFoundException;
113import java.io.FileOutputStream;
114import java.io.IOException;
115import java.io.InputStream;
116import java.lang.ref.WeakReference;
117import java.util.ArrayList;
118import java.util.HashMap;
svetoslavganov75986cf2009-05-14 22:28:01 -0700119import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import java.util.Iterator;
121import java.util.List;
122import java.util.Map;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700123import java.util.Map.Entry;
The Android Open Source Project10592532009-03-18 17:39:46 -0700124import java.util.Set;
svetoslavganov75986cf2009-05-14 22:28:01 -0700125import java.util.WeakHashMap;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700126import java.util.concurrent.CountDownLatch;
127import java.util.concurrent.ExecutorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129class ReceiverRestrictedContext extends ContextWrapper {
130 ReceiverRestrictedContext(Context base) {
131 super(base);
132 }
133
134 @Override
135 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
136 return registerReceiver(receiver, filter, null, null);
137 }
138
139 @Override
140 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
141 String broadcastPermission, Handler scheduler) {
142 throw new ReceiverCallNotAllowedException(
143 "IntentReceiver components are not allowed to register to receive intents");
144 //ex.fillInStackTrace();
145 //Log.e("IntentReceiver", ex.getMessage(), ex);
146 //return mContext.registerReceiver(receiver, filter, broadcastPermission,
147 // scheduler);
148 }
149
150 @Override
151 public boolean bindService(Intent service, ServiceConnection conn, int flags) {
152 throw new ReceiverCallNotAllowedException(
153 "IntentReceiver components are not allowed to bind to services");
154 //ex.fillInStackTrace();
155 //Log.e("IntentReceiver", ex.getMessage(), ex);
156 //return mContext.bindService(service, interfaceName, conn, flags);
157 }
158}
159
160/**
Dianne Hackborn21556372010-02-04 16:34:40 -0800161 * Common implementation of Context API, which provides the base
162 * context object for Activity and other application components.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 */
Dianne Hackborn21556372010-02-04 16:34:40 -0800164class ContextImpl extends Context {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 private final static String TAG = "ApplicationContext";
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700166 private final static boolean DEBUG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 private final static boolean DEBUG_ICONS = false;
168
169 private static final Object sSync = new Object();
170 private static AlarmManager sAlarmManager;
171 private static PowerManager sPowerManager;
172 private static ConnectivityManager sConnectivityManager;
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700173 private static ThrottleManager sThrottleManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 private static WifiManager sWifiManager;
175 private static LocationManager sLocationManager;
Bai Taoa58a8752010-07-13 15:32:16 +0800176 private static CountryDetector sCountryDetector;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700177 private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
178 new HashMap<String, SharedPreferencesImpl>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
180 private AudioManager mAudioManager;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700181 /*package*/ LoadedApk mPackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 private Resources mResources;
183 /*package*/ ActivityThread mMainThread;
184 private Context mOuterContext;
185 private IBinder mActivityToken = null;
186 private ApplicationContentResolver mContentResolver;
187 private int mThemeResource = 0;
188 private Resources.Theme mTheme = null;
189 private PackageManager mPackageManager;
190 private NotificationManager mNotificationManager = null;
191 private ActivityManager mActivityManager = null;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700192 private WallpaperManager mWallpaperManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 private Context mReceiverRestrictedContext = null;
194 private SearchManager mSearchManager = null;
195 private SensorManager mSensorManager = null;
San Mehatc9d81752010-02-01 10:23:27 -0800196 private StorageManager mStorageManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 private Vibrator mVibrator = null;
198 private LayoutInflater mLayoutInflater = null;
199 private StatusBarManager mStatusBarManager = null;
200 private TelephonyManager mTelephonyManager = null;
201 private ClipboardManager mClipboardManager = null;
Romain Guy870e09f2009-07-06 16:35:25 -0700202 private boolean mRestricted;
Fred Quintanae00a3112009-09-22 15:13:30 -0700203 private AccountManager mAccountManager; // protected by mSync
Dan Egnorf18a01c2009-11-12 11:32:50 -0800204 private DropBoxManager mDropBoxManager = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -0800205 private DevicePolicyManager mDevicePolicyManager = null;
Tobias Haamel53332882010-02-18 16:15:43 -0800206 private UiModeManager mUiModeManager = null;
Steve Howarda2709362010-07-02 17:12:48 -0700207 private DownloadManager mDownloadManager = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
209 private final Object mSync = new Object();
210
211 private File mDatabasesDir;
212 private File mPreferencesDir;
213 private File mFilesDir;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 private File mCacheDir;
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800215 private File mExternalFilesDir;
216 private File mExternalCacheDir;
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 private static final String[] EMPTY_FILE_LIST = {};
219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 @Override
221 public AssetManager getAssets() {
222 return mResources.getAssets();
223 }
224
225 @Override
226 public Resources getResources() {
227 return mResources;
228 }
229
230 @Override
231 public PackageManager getPackageManager() {
232 if (mPackageManager != null) {
233 return mPackageManager;
234 }
235
236 IPackageManager pm = ActivityThread.getPackageManager();
237 if (pm != null) {
238 // Doesn't matter if we make more than one instance.
239 return (mPackageManager = new ApplicationPackageManager(this, pm));
240 }
241
242 return null;
243 }
244
245 @Override
246 public ContentResolver getContentResolver() {
247 return mContentResolver;
248 }
249
250 @Override
251 public Looper getMainLooper() {
252 return mMainThread.getLooper();
253 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 @Override
256 public Context getApplicationContext() {
Christopher Tateeb9e9ec2010-03-23 17:14:36 -0700257 return (mPackageInfo != null) ?
258 mPackageInfo.getApplication() : mMainThread.getApplication();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 @Override
262 public void setTheme(int resid) {
263 mThemeResource = resid;
264 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 @Override
267 public Resources.Theme getTheme() {
268 if (mTheme == null) {
269 if (mThemeResource == 0) {
270 mThemeResource = com.android.internal.R.style.Theme;
271 }
272 mTheme = mResources.newTheme();
273 mTheme.applyStyle(mThemeResource, true);
274 }
275 return mTheme;
276 }
277
278 @Override
279 public ClassLoader getClassLoader() {
280 return mPackageInfo != null ?
281 mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
282 }
283
284 @Override
285 public String getPackageName() {
286 if (mPackageInfo != null) {
287 return mPackageInfo.getPackageName();
288 }
289 throw new RuntimeException("Not supported in system context");
290 }
291
292 @Override
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700293 public ApplicationInfo getApplicationInfo() {
294 if (mPackageInfo != null) {
295 return mPackageInfo.getApplicationInfo();
296 }
297 throw new RuntimeException("Not supported in system context");
298 }
299
300 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 public String getPackageResourcePath() {
302 if (mPackageInfo != null) {
303 return mPackageInfo.getResDir();
304 }
305 throw new RuntimeException("Not supported in system context");
306 }
307
308 @Override
309 public String getPackageCodePath() {
310 if (mPackageInfo != null) {
311 return mPackageInfo.getAppDir();
312 }
313 throw new RuntimeException("Not supported in system context");
314 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 private static File makeBackupFile(File prefsFile) {
317 return new File(prefsFile.getPath() + ".bak");
318 }
319
Joe Onorato23ecae32009-06-10 17:07:15 -0700320 public File getSharedPrefsFile(String name) {
321 return makeFilename(getPreferencesDir(), name + ".xml");
322 }
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 @Override
325 public SharedPreferences getSharedPreferences(String name, int mode) {
326 SharedPreferencesImpl sp;
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700327 File prefsFile;
328 boolean needInitialLoad = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 synchronized (sSharedPrefs) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -0700330 sp = sSharedPrefs.get(name);
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700331 if (sp != null && !sp.hasFileChangedUnexpectedly()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 return sp;
333 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700334 prefsFile = getSharedPrefsFile(name);
335 if (sp == null) {
336 sp = new SharedPreferencesImpl(prefsFile, mode, null);
337 sSharedPrefs.put(name, sp);
338 needInitialLoad = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 }
340 }
341
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700342 synchronized (sp) {
343 if (needInitialLoad && sp.isLoaded()) {
344 // lost the race to load; another thread handled it
345 return sp;
346 }
347 File backup = makeBackupFile(prefsFile);
348 if (backup.exists()) {
349 prefsFile.delete();
350 backup.renameTo(prefsFile);
351 }
352
353 // Debugging
354 if (prefsFile.exists() && !prefsFile.canRead()) {
355 Log.w(TAG, "Attempt to read preferences file " + prefsFile + " without permission");
356 }
357
358 Map map = null;
359 if (prefsFile.exists() && prefsFile.canRead()) {
360 try {
361 FileInputStream str = new FileInputStream(prefsFile);
362 map = XmlUtils.readMapXml(str);
363 str.close();
364 } catch (org.xmlpull.v1.XmlPullParserException e) {
365 Log.w(TAG, "getSharedPreferences", e);
366 } catch (FileNotFoundException e) {
367 Log.w(TAG, "getSharedPreferences", e);
368 } catch (IOException e) {
369 Log.w(TAG, "getSharedPreferences", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 }
371 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700372 sp.replace(map);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
Brad Fitzpatrick6194c532010-09-07 18:00:33 -0700374 return sp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376
377 private File getPreferencesDir() {
378 synchronized (mSync) {
379 if (mPreferencesDir == null) {
380 mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
381 }
382 return mPreferencesDir;
383 }
384 }
385
386 @Override
387 public FileInputStream openFileInput(String name)
388 throws FileNotFoundException {
389 File f = makeFilename(getFilesDir(), name);
390 return new FileInputStream(f);
391 }
392
393 @Override
394 public FileOutputStream openFileOutput(String name, int mode)
395 throws FileNotFoundException {
396 final boolean append = (mode&MODE_APPEND) != 0;
397 File f = makeFilename(getFilesDir(), name);
398 try {
399 FileOutputStream fos = new FileOutputStream(f, append);
400 setFilePermissionsFromMode(f.getPath(), mode, 0);
401 return fos;
402 } catch (FileNotFoundException e) {
403 }
404
405 File parent = f.getParentFile();
406 parent.mkdir();
407 FileUtils.setPermissions(
408 parent.getPath(),
409 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
410 -1, -1);
411 FileOutputStream fos = new FileOutputStream(f, append);
412 setFilePermissionsFromMode(f.getPath(), mode, 0);
413 return fos;
414 }
415
416 @Override
417 public boolean deleteFile(String name) {
418 File f = makeFilename(getFilesDir(), name);
419 return f.delete();
420 }
421
422 @Override
423 public File getFilesDir() {
424 synchronized (mSync) {
425 if (mFilesDir == null) {
426 mFilesDir = new File(getDataDirFile(), "files");
427 }
428 if (!mFilesDir.exists()) {
429 if(!mFilesDir.mkdirs()) {
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200430 Log.w(TAG, "Unable to create files directory " + mFilesDir.getPath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 return null;
432 }
433 FileUtils.setPermissions(
434 mFilesDir.getPath(),
435 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
436 -1, -1);
437 }
438 return mFilesDir;
439 }
440 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 @Override
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800443 public File getExternalFilesDir(String type) {
444 synchronized (mSync) {
445 if (mExternalFilesDir == null) {
446 mExternalFilesDir = Environment.getExternalStorageAppFilesDirectory(
447 getPackageName());
448 }
449 if (!mExternalFilesDir.exists()) {
450 try {
451 (new File(Environment.getExternalStorageAndroidDataDir(),
452 ".nomedia")).createNewFile();
453 } catch (IOException e) {
454 }
455 if (!mExternalFilesDir.mkdirs()) {
456 Log.w(TAG, "Unable to create external files directory");
457 return null;
458 }
459 }
460 if (type == null) {
461 return mExternalFilesDir;
462 }
463 File dir = new File(mExternalFilesDir, type);
464 if (!dir.exists()) {
465 if (!dir.mkdirs()) {
466 Log.w(TAG, "Unable to create external media directory " + dir);
467 return null;
468 }
469 }
470 return dir;
471 }
472 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200473
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800474 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 public File getCacheDir() {
476 synchronized (mSync) {
477 if (mCacheDir == null) {
478 mCacheDir = new File(getDataDirFile(), "cache");
479 }
480 if (!mCacheDir.exists()) {
481 if(!mCacheDir.mkdirs()) {
482 Log.w(TAG, "Unable to create cache directory");
483 return null;
484 }
485 FileUtils.setPermissions(
486 mCacheDir.getPath(),
487 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
488 -1, -1);
489 }
490 }
491 return mCacheDir;
492 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200493
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800494 @Override
495 public File getExternalCacheDir() {
496 synchronized (mSync) {
497 if (mExternalCacheDir == null) {
498 mExternalCacheDir = Environment.getExternalStorageAppCacheDirectory(
499 getPackageName());
500 }
501 if (!mExternalCacheDir.exists()) {
502 try {
503 (new File(Environment.getExternalStorageAndroidDataDir(),
504 ".nomedia")).createNewFile();
505 } catch (IOException e) {
506 }
507 if (!mExternalCacheDir.mkdirs()) {
508 Log.w(TAG, "Unable to create external cache directory");
509 return null;
510 }
511 }
512 return mExternalCacheDir;
513 }
514 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 @Override
517 public File getFileStreamPath(String name) {
518 return makeFilename(getFilesDir(), name);
519 }
520
521 @Override
522 public String[] fileList() {
523 final String[] list = getFilesDir().list();
524 return (list != null) ? list : EMPTY_FILE_LIST;
525 }
526
527 @Override
528 public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800529 File f = validateFilePath(name, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
531 setFilePermissionsFromMode(f.getPath(), mode, 0);
532 return db;
533 }
534
535 @Override
Vasu Nori74f170f2010-06-01 18:06:18 -0700536 public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
537 DatabaseErrorHandler errorHandler) {
538 File f = validateFilePath(name, true);
539 SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f.getPath(), factory, errorHandler);
540 setFilePermissionsFromMode(f.getPath(), mode, 0);
541 return db;
542 }
543
544 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 public boolean deleteDatabase(String name) {
546 try {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800547 File f = validateFilePath(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 return f.delete();
549 } catch (Exception e) {
550 }
551 return false;
552 }
553
554 @Override
555 public File getDatabasePath(String name) {
Oscar Montemayora8529f62009-11-18 10:14:20 -0800556 return validateFilePath(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
558
559 @Override
560 public String[] databaseList() {
561 final String[] list = getDatabasesDir().list();
562 return (list != null) ? list : EMPTY_FILE_LIST;
563 }
564
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 private File getDatabasesDir() {
567 synchronized (mSync) {
568 if (mDatabasesDir == null) {
569 mDatabasesDir = new File(getDataDirFile(), "databases");
570 }
571 if (mDatabasesDir.getPath().equals("databases")) {
572 mDatabasesDir = new File("/data/system");
573 }
574 return mDatabasesDir;
575 }
576 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 @Override
579 public Drawable getWallpaper() {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700580 return getWallpaperManager().getDrawable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 }
582
583 @Override
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700584 public Drawable peekWallpaper() {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700585 return getWallpaperManager().peekDrawable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 }
587
588 @Override
589 public int getWallpaperDesiredMinimumWidth() {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700590 return getWallpaperManager().getDesiredMinimumWidth();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
592
593 @Override
594 public int getWallpaperDesiredMinimumHeight() {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700595 return getWallpaperManager().getDesiredMinimumHeight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 }
597
598 @Override
599 public void setWallpaper(Bitmap bitmap) throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700600 getWallpaperManager().setBitmap(bitmap);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 }
602
603 @Override
604 public void setWallpaper(InputStream data) throws IOException {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700605 getWallpaperManager().setStream(data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 }
607
608 @Override
609 public void clearWallpaper() throws IOException {
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700610 getWallpaperManager().clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 }
612
613 @Override
614 public void startActivity(Intent intent) {
615 if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
616 throw new AndroidRuntimeException(
617 "Calling startActivity() from outside of an Activity "
618 + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
619 + " Is this really what you want?");
620 }
621 mMainThread.getInstrumentation().execStartActivity(
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700622 getOuterContext(), mMainThread.getApplicationThread(), null,
623 (Activity)null, intent, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 }
625
626 @Override
Dianne Hackbornfa82f222009-09-17 15:14:12 -0700627 public void startIntentSender(IntentSender intent,
628 Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
629 throws IntentSender.SendIntentException {
630 try {
631 String resolvedType = null;
632 if (fillInIntent != null) {
633 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
634 }
635 int result = ActivityManagerNative.getDefault()
636 .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
637 fillInIntent, resolvedType, null, null,
638 0, flagsMask, flagsValues);
639 if (result == IActivityManager.START_CANCELED) {
640 throw new IntentSender.SendIntentException();
641 }
642 Instrumentation.checkStartActivityResult(result, null);
643 } catch (RemoteException e) {
644 }
645 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +0200646
Dianne Hackbornfa82f222009-09-17 15:14:12 -0700647 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 public void sendBroadcast(Intent intent) {
649 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
650 try {
651 ActivityManagerNative.getDefault().broadcastIntent(
652 mMainThread.getApplicationThread(), intent, resolvedType, null,
653 Activity.RESULT_OK, null, null, null, false, false);
654 } catch (RemoteException e) {
655 }
656 }
657
658 @Override
659 public void sendBroadcast(Intent intent, String receiverPermission) {
660 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
661 try {
662 ActivityManagerNative.getDefault().broadcastIntent(
663 mMainThread.getApplicationThread(), intent, resolvedType, null,
664 Activity.RESULT_OK, null, null, receiverPermission, false, false);
665 } catch (RemoteException e) {
666 }
667 }
668
669 @Override
670 public void sendOrderedBroadcast(Intent intent,
671 String receiverPermission) {
672 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
673 try {
674 ActivityManagerNative.getDefault().broadcastIntent(
675 mMainThread.getApplicationThread(), intent, resolvedType, null,
676 Activity.RESULT_OK, null, null, receiverPermission, true, false);
677 } catch (RemoteException e) {
678 }
679 }
680
681 @Override
682 public void sendOrderedBroadcast(Intent intent,
683 String receiverPermission, BroadcastReceiver resultReceiver,
684 Handler scheduler, int initialCode, String initialData,
685 Bundle initialExtras) {
686 IIntentReceiver rd = null;
687 if (resultReceiver != null) {
688 if (mPackageInfo != null) {
689 if (scheduler == null) {
690 scheduler = mMainThread.getHandler();
691 }
692 rd = mPackageInfo.getReceiverDispatcher(
693 resultReceiver, getOuterContext(), scheduler,
694 mMainThread.getInstrumentation(), false);
695 } else {
696 if (scheduler == null) {
697 scheduler = mMainThread.getHandler();
698 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700699 rd = new LoadedApk.ReceiverDispatcher(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
701 }
702 }
703 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
704 try {
705 ActivityManagerNative.getDefault().broadcastIntent(
706 mMainThread.getApplicationThread(), intent, resolvedType, rd,
707 initialCode, initialData, initialExtras, receiverPermission,
708 true, false);
709 } catch (RemoteException e) {
710 }
711 }
712
713 @Override
714 public void sendStickyBroadcast(Intent intent) {
715 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
716 try {
717 ActivityManagerNative.getDefault().broadcastIntent(
718 mMainThread.getApplicationThread(), intent, resolvedType, null,
719 Activity.RESULT_OK, null, null, null, false, true);
720 } catch (RemoteException e) {
721 }
722 }
723
724 @Override
Dianne Hackbornefa199f2009-09-19 12:03:15 -0700725 public void sendStickyOrderedBroadcast(Intent intent,
726 BroadcastReceiver resultReceiver,
727 Handler scheduler, int initialCode, String initialData,
728 Bundle initialExtras) {
729 IIntentReceiver rd = null;
730 if (resultReceiver != null) {
731 if (mPackageInfo != null) {
732 if (scheduler == null) {
733 scheduler = mMainThread.getHandler();
734 }
735 rd = mPackageInfo.getReceiverDispatcher(
736 resultReceiver, getOuterContext(), scheduler,
737 mMainThread.getInstrumentation(), false);
738 } else {
739 if (scheduler == null) {
740 scheduler = mMainThread.getHandler();
741 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700742 rd = new LoadedApk.ReceiverDispatcher(
Dianne Hackbornefa199f2009-09-19 12:03:15 -0700743 resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
744 }
745 }
746 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
747 try {
748 ActivityManagerNative.getDefault().broadcastIntent(
749 mMainThread.getApplicationThread(), intent, resolvedType, rd,
750 initialCode, initialData, initialExtras, null,
751 true, true);
752 } catch (RemoteException e) {
753 }
754 }
755
756 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 public void removeStickyBroadcast(Intent intent) {
758 String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
759 if (resolvedType != null) {
760 intent = new Intent(intent);
761 intent.setDataAndType(intent.getData(), resolvedType);
762 }
763 try {
764 ActivityManagerNative.getDefault().unbroadcastIntent(
765 mMainThread.getApplicationThread(), intent);
766 } catch (RemoteException e) {
767 }
768 }
769
770 @Override
771 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
772 return registerReceiver(receiver, filter, null, null);
773 }
774
775 @Override
776 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
777 String broadcastPermission, Handler scheduler) {
778 return registerReceiverInternal(receiver, filter, broadcastPermission,
779 scheduler, getOuterContext());
780 }
781
782 private Intent registerReceiverInternal(BroadcastReceiver receiver,
783 IntentFilter filter, String broadcastPermission,
784 Handler scheduler, Context context) {
785 IIntentReceiver rd = null;
786 if (receiver != null) {
787 if (mPackageInfo != null && context != null) {
788 if (scheduler == null) {
789 scheduler = mMainThread.getHandler();
790 }
791 rd = mPackageInfo.getReceiverDispatcher(
792 receiver, context, scheduler,
793 mMainThread.getInstrumentation(), true);
794 } else {
795 if (scheduler == null) {
796 scheduler = mMainThread.getHandler();
797 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -0700798 rd = new LoadedApk.ReceiverDispatcher(
Dianne Hackborn399cccb2010-04-13 22:57:49 -0700799 receiver, context, scheduler, null, true).getIIntentReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 }
801 }
802 try {
803 return ActivityManagerNative.getDefault().registerReceiver(
804 mMainThread.getApplicationThread(),
805 rd, filter, broadcastPermission);
806 } catch (RemoteException e) {
807 return null;
808 }
809 }
810
811 @Override
812 public void unregisterReceiver(BroadcastReceiver receiver) {
813 if (mPackageInfo != null) {
814 IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
815 getOuterContext(), receiver);
816 try {
817 ActivityManagerNative.getDefault().unregisterReceiver(rd);
818 } catch (RemoteException e) {
819 }
820 } else {
821 throw new RuntimeException("Not supported in system context");
822 }
823 }
824
825 @Override
826 public ComponentName startService(Intent service) {
827 try {
828 ComponentName cn = ActivityManagerNative.getDefault().startService(
829 mMainThread.getApplicationThread(), service,
830 service.resolveTypeIfNeeded(getContentResolver()));
831 if (cn != null && cn.getPackageName().equals("!")) {
832 throw new SecurityException(
833 "Not allowed to start service " + service
834 + " without permission " + cn.getClassName());
835 }
836 return cn;
837 } catch (RemoteException e) {
838 return null;
839 }
840 }
841
842 @Override
843 public boolean stopService(Intent service) {
844 try {
845 int res = ActivityManagerNative.getDefault().stopService(
846 mMainThread.getApplicationThread(), service,
847 service.resolveTypeIfNeeded(getContentResolver()));
848 if (res < 0) {
849 throw new SecurityException(
850 "Not allowed to stop service " + service);
851 }
852 return res != 0;
853 } catch (RemoteException e) {
854 return false;
855 }
856 }
857
858 @Override
859 public boolean bindService(Intent service, ServiceConnection conn,
860 int flags) {
861 IServiceConnection sd;
862 if (mPackageInfo != null) {
863 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
864 mMainThread.getHandler(), flags);
865 } else {
866 throw new RuntimeException("Not supported in system context");
867 }
868 try {
869 int res = ActivityManagerNative.getDefault().bindService(
870 mMainThread.getApplicationThread(), getActivityToken(),
871 service, service.resolveTypeIfNeeded(getContentResolver()),
872 sd, flags);
873 if (res < 0) {
874 throw new SecurityException(
875 "Not allowed to bind to service " + service);
876 }
877 return res != 0;
878 } catch (RemoteException e) {
879 return false;
880 }
881 }
882
883 @Override
884 public void unbindService(ServiceConnection conn) {
885 if (mPackageInfo != null) {
886 IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
887 getOuterContext(), conn);
888 try {
889 ActivityManagerNative.getDefault().unbindService(sd);
890 } catch (RemoteException e) {
891 }
892 } else {
893 throw new RuntimeException("Not supported in system context");
894 }
895 }
896
897 @Override
898 public boolean startInstrumentation(ComponentName className,
899 String profileFile, Bundle arguments) {
900 try {
901 return ActivityManagerNative.getDefault().startInstrumentation(
902 className, profileFile, 0, arguments, null);
903 } catch (RemoteException e) {
904 // System has crashed, nothing we can do.
905 }
906 return false;
907 }
908
909 @Override
910 public Object getSystemService(String name) {
911 if (WINDOW_SERVICE.equals(name)) {
912 return WindowManagerImpl.getDefault();
913 } else if (LAYOUT_INFLATER_SERVICE.equals(name)) {
914 synchronized (mSync) {
915 LayoutInflater inflater = mLayoutInflater;
916 if (inflater != null) {
917 return inflater;
918 }
919 mLayoutInflater = inflater =
920 PolicyManager.makeNewLayoutInflater(getOuterContext());
921 return inflater;
922 }
923 } else if (ACTIVITY_SERVICE.equals(name)) {
924 return getActivityManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700925 } else if (INPUT_METHOD_SERVICE.equals(name)) {
926 return InputMethodManager.getInstance(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 } else if (ALARM_SERVICE.equals(name)) {
928 return getAlarmManager();
Fred Quintana60307342009-03-24 22:48:12 -0700929 } else if (ACCOUNT_SERVICE.equals(name)) {
930 return getAccountManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 } else if (POWER_SERVICE.equals(name)) {
932 return getPowerManager();
933 } else if (CONNECTIVITY_SERVICE.equals(name)) {
934 return getConnectivityManager();
Irfan Sheriffc9b68512010-04-08 14:12:33 -0700935 } else if (THROTTLE_SERVICE.equals(name)) {
936 return getThrottleManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 } else if (WIFI_SERVICE.equals(name)) {
938 return getWifiManager();
939 } else if (NOTIFICATION_SERVICE.equals(name)) {
940 return getNotificationManager();
941 } else if (KEYGUARD_SERVICE.equals(name)) {
942 return new KeyguardManager();
svetoslavganov75986cf2009-05-14 22:28:01 -0700943 } else if (ACCESSIBILITY_SERVICE.equals(name)) {
944 return AccessibilityManager.getInstance(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 } else if (LOCATION_SERVICE.equals(name)) {
946 return getLocationManager();
Bai Taoa58a8752010-07-13 15:32:16 +0800947 } else if (COUNTRY_DETECTOR.equals(name)) {
948 return getCountryDetector();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 } else if (SEARCH_SERVICE.equals(name)) {
950 return getSearchManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700951 } else if (SENSOR_SERVICE.equals(name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 return getSensorManager();
San Mehatc9d81752010-02-01 10:23:27 -0800953 } else if (STORAGE_SERVICE.equals(name)) {
954 return getStorageManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 } else if (VIBRATOR_SERVICE.equals(name)) {
956 return getVibrator();
957 } else if (STATUS_BAR_SERVICE.equals(name)) {
958 synchronized (mSync) {
959 if (mStatusBarManager == null) {
960 mStatusBarManager = new StatusBarManager(getOuterContext());
961 }
962 return mStatusBarManager;
963 }
964 } else if (AUDIO_SERVICE.equals(name)) {
965 return getAudioManager();
966 } else if (TELEPHONY_SERVICE.equals(name)) {
967 return getTelephonyManager();
968 } else if (CLIPBOARD_SERVICE.equals(name)) {
969 return getClipboardManager();
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700970 } else if (WALLPAPER_SERVICE.equals(name)) {
971 return getWallpaperManager();
Dan Egnor95240272009-10-27 18:23:39 -0700972 } else if (DROPBOX_SERVICE.equals(name)) {
Dan Egnorf18a01c2009-11-12 11:32:50 -0800973 return getDropBoxManager();
Dianne Hackbornd6847842010-01-12 18:14:19 -0800974 } else if (DEVICE_POLICY_SERVICE.equals(name)) {
975 return getDevicePolicyManager();
Tobias Haamel69fb5742010-02-22 21:54:05 +0100976 } else if (UI_MODE_SERVICE.equals(name)) {
Tobias Haamel53332882010-02-18 16:15:43 -0800977 return getUiModeManager();
Steve Howarda2709362010-07-02 17:12:48 -0700978 } else if (DOWNLOAD_SERVICE.equals(name)) {
979 return getDownloadManager();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981
982 return null;
983 }
984
Fred Quintana60307342009-03-24 22:48:12 -0700985 private AccountManager getAccountManager() {
Fred Quintanae00a3112009-09-22 15:13:30 -0700986 synchronized (mSync) {
987 if (mAccountManager == null) {
Fred Quintana60307342009-03-24 22:48:12 -0700988 IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
989 IAccountManager service = IAccountManager.Stub.asInterface(b);
Fred Quintanae00a3112009-09-22 15:13:30 -0700990 mAccountManager = new AccountManager(this, service);
Fred Quintana60307342009-03-24 22:48:12 -0700991 }
Fred Quintanae00a3112009-09-22 15:13:30 -0700992 return mAccountManager;
Fred Quintana60307342009-03-24 22:48:12 -0700993 }
Fred Quintana60307342009-03-24 22:48:12 -0700994 }
995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 private ActivityManager getActivityManager() {
997 synchronized (mSync) {
998 if (mActivityManager == null) {
999 mActivityManager = new ActivityManager(getOuterContext(),
1000 mMainThread.getHandler());
1001 }
1002 }
1003 return mActivityManager;
1004 }
1005
1006 private AlarmManager getAlarmManager() {
1007 synchronized (sSync) {
1008 if (sAlarmManager == null) {
1009 IBinder b = ServiceManager.getService(ALARM_SERVICE);
1010 IAlarmManager service = IAlarmManager.Stub.asInterface(b);
1011 sAlarmManager = new AlarmManager(service);
1012 }
1013 }
1014 return sAlarmManager;
1015 }
1016
1017 private PowerManager getPowerManager() {
1018 synchronized (sSync) {
1019 if (sPowerManager == null) {
1020 IBinder b = ServiceManager.getService(POWER_SERVICE);
1021 IPowerManager service = IPowerManager.Stub.asInterface(b);
1022 sPowerManager = new PowerManager(service, mMainThread.getHandler());
1023 }
1024 }
1025 return sPowerManager;
1026 }
1027
1028 private ConnectivityManager getConnectivityManager()
1029 {
1030 synchronized (sSync) {
1031 if (sConnectivityManager == null) {
1032 IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
1033 IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
1034 sConnectivityManager = new ConnectivityManager(service);
1035 }
1036 }
1037 return sConnectivityManager;
1038 }
1039
Irfan Sheriffc9b68512010-04-08 14:12:33 -07001040 private ThrottleManager getThrottleManager()
1041 {
1042 synchronized (sSync) {
1043 if (sThrottleManager == null) {
1044 IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
1045 IThrottleManager service = IThrottleManager.Stub.asInterface(b);
1046 sThrottleManager = new ThrottleManager(service);
1047 }
1048 }
1049 return sThrottleManager;
1050 }
1051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 private WifiManager getWifiManager()
1053 {
1054 synchronized (sSync) {
1055 if (sWifiManager == null) {
1056 IBinder b = ServiceManager.getService(WIFI_SERVICE);
1057 IWifiManager service = IWifiManager.Stub.asInterface(b);
1058 sWifiManager = new WifiManager(service, mMainThread.getHandler());
1059 }
1060 }
1061 return sWifiManager;
1062 }
1063
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001064 private NotificationManager getNotificationManager() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 synchronized (mSync) {
1066 if (mNotificationManager == null) {
Adam Powellc63806d2010-09-23 16:21:30 -07001067 final Context outerContext = getOuterContext();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 mNotificationManager = new NotificationManager(
Adam Powellc63806d2010-09-23 16:21:30 -07001069 new ContextThemeWrapper(outerContext,
1070 outerContext.getApplicationInfo().targetSdkVersion >=
1071 Build.VERSION_CODES.HONEYCOMB
1072 ? com.android.internal.R.style.Theme_Holo_Dialog
1073 : com.android.internal.R.style.Theme_Dialog),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 mMainThread.getHandler());
1075 }
1076 }
1077 return mNotificationManager;
1078 }
1079
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001080 private WallpaperManager getWallpaperManager() {
1081 synchronized (mSync) {
1082 if (mWallpaperManager == null) {
1083 mWallpaperManager = new WallpaperManager(getOuterContext(),
1084 mMainThread.getHandler());
1085 }
1086 }
1087 return mWallpaperManager;
1088 }
1089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 private TelephonyManager getTelephonyManager() {
1091 synchronized (mSync) {
1092 if (mTelephonyManager == null) {
1093 mTelephonyManager = new TelephonyManager(getOuterContext());
1094 }
1095 }
1096 return mTelephonyManager;
1097 }
1098
1099 private ClipboardManager getClipboardManager() {
1100 synchronized (mSync) {
1101 if (mClipboardManager == null) {
1102 mClipboardManager = new ClipboardManager(getOuterContext(),
1103 mMainThread.getHandler());
1104 }
1105 }
1106 return mClipboardManager;
1107 }
1108
1109 private LocationManager getLocationManager() {
1110 synchronized (sSync) {
1111 if (sLocationManager == null) {
1112 IBinder b = ServiceManager.getService(LOCATION_SERVICE);
1113 ILocationManager service = ILocationManager.Stub.asInterface(b);
1114 sLocationManager = new LocationManager(service);
1115 }
1116 }
1117 return sLocationManager;
1118 }
1119
Bai Taoa58a8752010-07-13 15:32:16 +08001120 private CountryDetector getCountryDetector() {
1121 synchronized (sSync) {
1122 if (sCountryDetector == null) {
1123 IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
1124 ICountryDetector service = ICountryDetector.Stub.asInterface(b);
1125 sCountryDetector = new CountryDetector(service);
1126 }
1127 }
1128 return sCountryDetector;
1129 }
1130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 private SearchManager getSearchManager() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 synchronized (mSync) {
1133 if (mSearchManager == null) {
1134 mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
1135 }
1136 }
1137 return mSearchManager;
1138 }
1139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 private SensorManager getSensorManager() {
1141 synchronized (mSync) {
1142 if (mSensorManager == null) {
1143 mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());
1144 }
1145 }
1146 return mSensorManager;
1147 }
1148
San Mehatc9d81752010-02-01 10:23:27 -08001149 private StorageManager getStorageManager() {
1150 synchronized (mSync) {
1151 if (mStorageManager == null) {
1152 try {
1153 mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
1154 } catch (RemoteException rex) {
1155 Log.e(TAG, "Failed to create StorageManager", rex);
1156 mStorageManager = null;
1157 }
1158 }
1159 }
1160 return mStorageManager;
1161 }
1162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 private Vibrator getVibrator() {
1164 synchronized (mSync) {
1165 if (mVibrator == null) {
1166 mVibrator = new Vibrator();
1167 }
1168 }
1169 return mVibrator;
1170 }
Dan Egnor95240272009-10-27 18:23:39 -07001171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 private AudioManager getAudioManager()
1173 {
1174 if (mAudioManager == null) {
1175 mAudioManager = new AudioManager(this);
1176 }
1177 return mAudioManager;
1178 }
1179
Brad Fitzpatrick438d0592010-06-10 12:19:19 -07001180 /* package */ static DropBoxManager createDropBoxManager() {
1181 IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
1182 IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
1183 return new DropBoxManager(service);
1184 }
1185
Dan Egnorf18a01c2009-11-12 11:32:50 -08001186 private DropBoxManager getDropBoxManager() {
Dan Egnor95240272009-10-27 18:23:39 -07001187 synchronized (mSync) {
Dan Egnorf18a01c2009-11-12 11:32:50 -08001188 if (mDropBoxManager == null) {
Brad Fitzpatrick438d0592010-06-10 12:19:19 -07001189 mDropBoxManager = createDropBoxManager();
Dan Egnor95240272009-10-27 18:23:39 -07001190 }
1191 }
Dan Egnorf18a01c2009-11-12 11:32:50 -08001192 return mDropBoxManager;
Dan Egnor95240272009-10-27 18:23:39 -07001193 }
1194
Dianne Hackbornd6847842010-01-12 18:14:19 -08001195 private DevicePolicyManager getDevicePolicyManager() {
1196 synchronized (mSync) {
1197 if (mDevicePolicyManager == null) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001198 mDevicePolicyManager = DevicePolicyManager.create(this,
Dianne Hackbornd6847842010-01-12 18:14:19 -08001199 mMainThread.getHandler());
1200 }
1201 }
1202 return mDevicePolicyManager;
1203 }
1204
Tobias Haamel53332882010-02-18 16:15:43 -08001205 private UiModeManager getUiModeManager() {
1206 synchronized (mSync) {
1207 if (mUiModeManager == null) {
1208 mUiModeManager = new UiModeManager();
1209 }
1210 }
1211 return mUiModeManager;
1212 }
1213
Steve Howarda2709362010-07-02 17:12:48 -07001214 private DownloadManager getDownloadManager() {
1215 synchronized (mSync) {
1216 if (mDownloadManager == null) {
Steve Howardb8e07a52010-07-21 14:53:21 -07001217 mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
Steve Howarda2709362010-07-02 17:12:48 -07001218 }
1219 }
1220 return mDownloadManager;
1221 }
1222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 @Override
1224 public int checkPermission(String permission, int pid, int uid) {
1225 if (permission == null) {
1226 throw new IllegalArgumentException("permission is null");
1227 }
1228
1229 if (!Process.supportsProcesses()) {
1230 return PackageManager.PERMISSION_GRANTED;
1231 }
1232 try {
1233 return ActivityManagerNative.getDefault().checkPermission(
1234 permission, pid, uid);
1235 } catch (RemoteException e) {
1236 return PackageManager.PERMISSION_DENIED;
1237 }
1238 }
1239
1240 @Override
1241 public int checkCallingPermission(String permission) {
1242 if (permission == null) {
1243 throw new IllegalArgumentException("permission is null");
1244 }
1245
1246 if (!Process.supportsProcesses()) {
1247 return PackageManager.PERMISSION_GRANTED;
1248 }
1249 int pid = Binder.getCallingPid();
1250 if (pid != Process.myPid()) {
1251 return checkPermission(permission, pid,
1252 Binder.getCallingUid());
1253 }
1254 return PackageManager.PERMISSION_DENIED;
1255 }
1256
1257 @Override
1258 public int checkCallingOrSelfPermission(String permission) {
1259 if (permission == null) {
1260 throw new IllegalArgumentException("permission is null");
1261 }
1262
1263 return checkPermission(permission, Binder.getCallingPid(),
1264 Binder.getCallingUid());
1265 }
1266
1267 private void enforce(
1268 String permission, int resultOfCheck,
1269 boolean selfToo, int uid, String message) {
1270 if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1271 throw new SecurityException(
1272 (message != null ? (message + ": ") : "") +
1273 (selfToo
1274 ? "Neither user " + uid + " nor current process has "
1275 : "User " + uid + " does not have ") +
1276 permission +
1277 ".");
1278 }
1279 }
1280
1281 public void enforcePermission(
1282 String permission, int pid, int uid, String message) {
1283 enforce(permission,
1284 checkPermission(permission, pid, uid),
1285 false,
1286 uid,
1287 message);
1288 }
1289
1290 public void enforceCallingPermission(String permission, String message) {
1291 enforce(permission,
1292 checkCallingPermission(permission),
1293 false,
1294 Binder.getCallingUid(),
1295 message);
1296 }
1297
1298 public void enforceCallingOrSelfPermission(
1299 String permission, String message) {
1300 enforce(permission,
1301 checkCallingOrSelfPermission(permission),
1302 true,
1303 Binder.getCallingUid(),
1304 message);
1305 }
1306
1307 @Override
1308 public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
1309 try {
1310 ActivityManagerNative.getDefault().grantUriPermission(
1311 mMainThread.getApplicationThread(), toPackage, uri,
1312 modeFlags);
1313 } catch (RemoteException e) {
1314 }
1315 }
1316
1317 @Override
1318 public void revokeUriPermission(Uri uri, int modeFlags) {
1319 try {
1320 ActivityManagerNative.getDefault().revokeUriPermission(
1321 mMainThread.getApplicationThread(), uri,
1322 modeFlags);
1323 } catch (RemoteException e) {
1324 }
1325 }
1326
1327 @Override
1328 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
1329 if (!Process.supportsProcesses()) {
1330 return PackageManager.PERMISSION_GRANTED;
1331 }
1332 try {
1333 return ActivityManagerNative.getDefault().checkUriPermission(
1334 uri, pid, uid, modeFlags);
1335 } catch (RemoteException e) {
1336 return PackageManager.PERMISSION_DENIED;
1337 }
1338 }
1339
1340 @Override
1341 public int checkCallingUriPermission(Uri uri, int modeFlags) {
1342 if (!Process.supportsProcesses()) {
1343 return PackageManager.PERMISSION_GRANTED;
1344 }
1345 int pid = Binder.getCallingPid();
1346 if (pid != Process.myPid()) {
1347 return checkUriPermission(uri, pid,
1348 Binder.getCallingUid(), modeFlags);
1349 }
1350 return PackageManager.PERMISSION_DENIED;
1351 }
1352
1353 @Override
1354 public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
1355 return checkUriPermission(uri, Binder.getCallingPid(),
1356 Binder.getCallingUid(), modeFlags);
1357 }
1358
1359 @Override
1360 public int checkUriPermission(Uri uri, String readPermission,
1361 String writePermission, int pid, int uid, int modeFlags) {
Mitsuru Oshima569076c2009-07-02 20:06:08 -07001362 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission="
1364 + readPermission + " writePermission=" + writePermission
1365 + " pid=" + pid + " uid=" + uid + " mode" + modeFlags);
1366 }
1367 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
1368 if (readPermission == null
1369 || checkPermission(readPermission, pid, uid)
1370 == PackageManager.PERMISSION_GRANTED) {
1371 return PackageManager.PERMISSION_GRANTED;
1372 }
1373 }
1374 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
1375 if (writePermission == null
1376 || checkPermission(writePermission, pid, uid)
1377 == PackageManager.PERMISSION_GRANTED) {
1378 return PackageManager.PERMISSION_GRANTED;
1379 }
1380 }
1381 return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
1382 : PackageManager.PERMISSION_DENIED;
1383 }
1384
1385 private String uriModeFlagToString(int uriModeFlags) {
1386 switch (uriModeFlags) {
1387 case Intent.FLAG_GRANT_READ_URI_PERMISSION |
1388 Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1389 return "read and write";
1390 case Intent.FLAG_GRANT_READ_URI_PERMISSION:
1391 return "read";
1392 case Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1393 return "write";
1394 }
1395 throw new IllegalArgumentException(
1396 "Unknown permission mode flags: " + uriModeFlags);
1397 }
1398
1399 private void enforceForUri(
1400 int modeFlags, int resultOfCheck, boolean selfToo,
1401 int uid, Uri uri, String message) {
1402 if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1403 throw new SecurityException(
1404 (message != null ? (message + ": ") : "") +
1405 (selfToo
1406 ? "Neither user " + uid + " nor current process has "
1407 : "User " + uid + " does not have ") +
1408 uriModeFlagToString(modeFlags) +
1409 " permission on " +
1410 uri +
1411 ".");
1412 }
1413 }
1414
1415 public void enforceUriPermission(
1416 Uri uri, int pid, int uid, int modeFlags, String message) {
1417 enforceForUri(
1418 modeFlags, checkUriPermission(uri, pid, uid, modeFlags),
1419 false, uid, uri, message);
1420 }
1421
1422 public void enforceCallingUriPermission(
1423 Uri uri, int modeFlags, String message) {
1424 enforceForUri(
1425 modeFlags, checkCallingUriPermission(uri, modeFlags),
1426 false, Binder.getCallingUid(), uri, message);
1427 }
1428
1429 public void enforceCallingOrSelfUriPermission(
1430 Uri uri, int modeFlags, String message) {
1431 enforceForUri(
1432 modeFlags,
1433 checkCallingOrSelfUriPermission(uri, modeFlags), true,
1434 Binder.getCallingUid(), uri, message);
1435 }
1436
1437 public void enforceUriPermission(
1438 Uri uri, String readPermission, String writePermission,
1439 int pid, int uid, int modeFlags, String message) {
1440 enforceForUri(modeFlags,
1441 checkUriPermission(
1442 uri, readPermission, writePermission, pid, uid,
1443 modeFlags),
1444 false,
1445 uid,
1446 uri,
1447 message);
1448 }
1449
1450 @Override
1451 public Context createPackageContext(String packageName, int flags)
1452 throws PackageManager.NameNotFoundException {
1453 if (packageName.equals("system") || packageName.equals("android")) {
Dianne Hackborn21556372010-02-04 16:34:40 -08001454 return new ContextImpl(mMainThread.getSystemContext());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 }
1456
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001457 LoadedApk pi =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 mMainThread.getPackageInfo(packageName, flags);
1459 if (pi != null) {
Dianne Hackborn21556372010-02-04 16:34:40 -08001460 ContextImpl c = new ContextImpl();
Romain Guy870e09f2009-07-06 16:35:25 -07001461 c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001462 c.init(pi, null, mMainThread, mResources);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 if (c.mResources != null) {
1464 return c;
1465 }
1466 }
1467
1468 // Should be a better exception.
1469 throw new PackageManager.NameNotFoundException(
1470 "Application package " + packageName + " not found");
1471 }
1472
Romain Guy870e09f2009-07-06 16:35:25 -07001473 @Override
1474 public boolean isRestricted() {
1475 return mRestricted;
1476 }
1477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 private File getDataDirFile() {
1479 if (mPackageInfo != null) {
1480 return mPackageInfo.getDataDirFile();
1481 }
1482 throw new RuntimeException("Not supported in system context");
1483 }
1484
1485 @Override
1486 public File getDir(String name, int mode) {
1487 name = "app_" + name;
1488 File file = makeFilename(getDataDirFile(), name);
1489 if (!file.exists()) {
1490 file.mkdir();
1491 setFilePermissionsFromMode(file.getPath(), mode,
1492 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH);
1493 }
1494 return file;
1495 }
1496
Dianne Hackborn21556372010-02-04 16:34:40 -08001497 static ContextImpl createSystemContext(ActivityThread mainThread) {
1498 ContextImpl context = new ContextImpl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 context.init(Resources.getSystem(), mainThread);
1500 return context;
1501 }
1502
Dianne Hackborn21556372010-02-04 16:34:40 -08001503 ContextImpl() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 mOuterContext = this;
1505 }
1506
1507 /**
1508 * Create a new ApplicationContext from an existing one. The new one
1509 * works and operates the same as the one it is copying.
1510 *
1511 * @param context Existing application context.
1512 */
Dianne Hackborn21556372010-02-04 16:34:40 -08001513 public ContextImpl(ContextImpl context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 mPackageInfo = context.mPackageInfo;
1515 mResources = context.mResources;
1516 mMainThread = context.mMainThread;
1517 mContentResolver = context.mContentResolver;
1518 mOuterContext = this;
1519 }
1520
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001521 final void init(LoadedApk packageInfo,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 IBinder activityToken, ActivityThread mainThread) {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001523 init(packageInfo, activityToken, mainThread, null);
1524 }
1525
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001526 final void init(LoadedApk packageInfo,
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001527 IBinder activityToken, ActivityThread mainThread,
1528 Resources container) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 mPackageInfo = packageInfo;
1530 mResources = mPackageInfo.getResources(mainThread);
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001531
Dianne Hackborn559a7872010-04-07 18:19:41 -07001532 if (mResources != null && container != null
1533 && container.getCompatibilityInfo().applicationScale !=
1534 mResources.getCompatibilityInfo().applicationScale) {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -07001535 if (DEBUG) {
1536 Log.d(TAG, "loaded context has different scaling. Using container's" +
1537 " compatiblity info:" + container.getDisplayMetrics());
1538 }
1539 mResources = mainThread.getTopLevelResources(
1540 mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
1541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 mMainThread = mainThread;
1543 mContentResolver = new ApplicationContentResolver(this, mainThread);
1544
1545 setActivityToken(activityToken);
1546 }
1547
1548 final void init(Resources resources, ActivityThread mainThread) {
1549 mPackageInfo = null;
1550 mResources = resources;
1551 mMainThread = mainThread;
1552 mContentResolver = new ApplicationContentResolver(this, mainThread);
1553 }
1554
1555 final void scheduleFinalCleanup(String who, String what) {
1556 mMainThread.scheduleContextCleanup(this, who, what);
1557 }
1558
1559 final void performFinalCleanup(String who, String what) {
1560 //Log.i(TAG, "Cleanup up context: " + this);
1561 mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
1562 }
1563
1564 final Context getReceiverRestrictedContext() {
1565 if (mReceiverRestrictedContext != null) {
1566 return mReceiverRestrictedContext;
1567 }
1568 return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
1569 }
1570
1571 final void setActivityToken(IBinder token) {
1572 mActivityToken = token;
1573 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 final void setOuterContext(Context context) {
1576 mOuterContext = context;
1577 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 final Context getOuterContext() {
1580 return mOuterContext;
1581 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 final IBinder getActivityToken() {
1584 return mActivityToken;
1585 }
1586
1587 private static void setFilePermissionsFromMode(String name, int mode,
1588 int extraPermissions) {
1589 int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
1590 |FileUtils.S_IRGRP|FileUtils.S_IWGRP
1591 |extraPermissions;
1592 if ((mode&MODE_WORLD_READABLE) != 0) {
1593 perms |= FileUtils.S_IROTH;
1594 }
1595 if ((mode&MODE_WORLD_WRITEABLE) != 0) {
1596 perms |= FileUtils.S_IWOTH;
1597 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -07001598 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode)
1600 + ", perms=0x" + Integer.toHexString(perms));
1601 }
1602 FileUtils.setPermissions(name, perms, -1, -1);
1603 }
1604
Oscar Montemayora8529f62009-11-18 10:14:20 -08001605 private File validateFilePath(String name, boolean createDirectory) {
1606 File dir;
1607 File f;
1608
1609 if (name.charAt(0) == File.separatorChar) {
1610 String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
1611 dir = new File(dirPath);
1612 name = name.substring(name.lastIndexOf(File.separatorChar));
1613 f = new File(dir, name);
1614 } else {
1615 dir = getDatabasesDir();
1616 f = makeFilename(dir, name);
1617 }
1618
1619 if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
1620 FileUtils.setPermissions(dir.getPath(),
1621 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1622 -1, -1);
1623 }
1624
1625 return f;
1626 }
1627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 private File makeFilename(File base, String name) {
1629 if (name.indexOf(File.separatorChar) < 0) {
1630 return new File(base, name);
1631 }
1632 throw new IllegalArgumentException(
Oscar Montemayora8529f62009-11-18 10:14:20 -08001633 "File " + name + " contains a path separator");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 }
1635
1636 // ----------------------------------------------------------------------
1637 // ----------------------------------------------------------------------
1638 // ----------------------------------------------------------------------
1639
1640 private static final class ApplicationContentResolver extends ContentResolver {
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001641 public ApplicationContentResolver(Context context, ActivityThread mainThread) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 super(context);
1643 mMainThread = mainThread;
1644 }
1645
1646 @Override
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001647 protected IContentProvider acquireProvider(Context context, String name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 return mMainThread.acquireProvider(context, name);
1649 }
1650
1651 @Override
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001652 protected IContentProvider acquireExistingProvider(Context context, String name) {
1653 return mMainThread.acquireExistingProvider(context, name);
1654 }
1655
1656 @Override
1657 public boolean releaseProvider(IContentProvider provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 return mMainThread.releaseProvider(provider);
1659 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 private final ActivityThread mMainThread;
1662 }
1663
1664 // ----------------------------------------------------------------------
1665 // ----------------------------------------------------------------------
1666 // ----------------------------------------------------------------------
1667
1668 /*package*/
1669 static final class ApplicationPackageManager extends PackageManager {
1670 @Override
1671 public PackageInfo getPackageInfo(String packageName, int flags)
1672 throws NameNotFoundException {
1673 try {
1674 PackageInfo pi = mPM.getPackageInfo(packageName, flags);
1675 if (pi != null) {
1676 return pi;
1677 }
1678 } catch (RemoteException e) {
1679 throw new RuntimeException("Package manager has died", e);
1680 }
1681
1682 throw new NameNotFoundException(packageName);
1683 }
1684
Mihai Predaeae850c2009-05-13 10:13:48 +02001685 @Override
Dianne Hackborn47096932010-02-11 15:57:09 -08001686 public String[] currentToCanonicalPackageNames(String[] names) {
1687 try {
1688 return mPM.currentToCanonicalPackageNames(names);
1689 } catch (RemoteException e) {
1690 throw new RuntimeException("Package manager has died", e);
1691 }
1692 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001693
Dianne Hackborn47096932010-02-11 15:57:09 -08001694 @Override
1695 public String[] canonicalToCurrentPackageNames(String[] names) {
1696 try {
1697 return mPM.canonicalToCurrentPackageNames(names);
1698 } catch (RemoteException e) {
1699 throw new RuntimeException("Package manager has died", e);
1700 }
1701 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001702
Dianne Hackborn47096932010-02-11 15:57:09 -08001703 @Override
Mihai Predaeae850c2009-05-13 10:13:48 +02001704 public Intent getLaunchIntentForPackage(String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 // First see if the package has an INFO activity; the existence of
1706 // such an activity is implied to be the desired front-door for the
1707 // overall package (such as if it has multiple launcher entries).
Mihai Predaeae850c2009-05-13 10:13:48 +02001708 Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1709 intentToResolve.addCategory(Intent.CATEGORY_INFO);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07001710 intentToResolve.setPackage(packageName);
1711 ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0);
Mihai Predaeae850c2009-05-13 10:13:48 +02001712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 // Otherwise, try to find a main launcher activity.
Mihai Predaeae850c2009-05-13 10:13:48 +02001714 if (resolveInfo == null) {
1715 // reuse the intent instance
1716 intentToResolve.removeCategory(Intent.CATEGORY_INFO);
1717 intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07001718 intentToResolve.setPackage(packageName);
1719 resolveInfo = resolveActivity(intentToResolve, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
Mihai Predaeae850c2009-05-13 10:13:48 +02001721 if (resolveInfo == null) {
1722 return null;
1723 }
Johan Erlandssondf4cfa362010-03-31 08:20:51 +02001724 Intent intent = new Intent(intentToResolve);
1725 intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName,
1726 resolveInfo.activityInfo.name);
Mihai Predaeae850c2009-05-13 10:13:48 +02001727 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1728 return intent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
Mihai Predaeae850c2009-05-13 10:13:48 +02001730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 @Override
1732 public int[] getPackageGids(String packageName)
1733 throws NameNotFoundException {
1734 try {
1735 int[] gids = mPM.getPackageGids(packageName);
1736 if (gids == null || gids.length > 0) {
1737 return gids;
1738 }
1739 } catch (RemoteException e) {
1740 throw new RuntimeException("Package manager has died", e);
1741 }
1742
1743 throw new NameNotFoundException(packageName);
1744 }
1745
1746 @Override
1747 public PermissionInfo getPermissionInfo(String name, int flags)
1748 throws NameNotFoundException {
1749 try {
1750 PermissionInfo pi = mPM.getPermissionInfo(name, flags);
1751 if (pi != null) {
1752 return pi;
1753 }
1754 } catch (RemoteException e) {
1755 throw new RuntimeException("Package manager has died", e);
1756 }
1757
1758 throw new NameNotFoundException(name);
1759 }
1760
1761 @Override
1762 public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
1763 throws NameNotFoundException {
1764 try {
1765 List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
1766 if (pi != null) {
1767 return pi;
1768 }
1769 } catch (RemoteException e) {
1770 throw new RuntimeException("Package manager has died", e);
1771 }
1772
1773 throw new NameNotFoundException(group);
1774 }
1775
1776 @Override
1777 public PermissionGroupInfo getPermissionGroupInfo(String name,
1778 int flags) throws NameNotFoundException {
1779 try {
1780 PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
1781 if (pgi != null) {
1782 return pgi;
1783 }
1784 } catch (RemoteException e) {
1785 throw new RuntimeException("Package manager has died", e);
1786 }
1787
1788 throw new NameNotFoundException(name);
1789 }
1790
1791 @Override
1792 public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
1793 try {
1794 return mPM.getAllPermissionGroups(flags);
1795 } catch (RemoteException e) {
1796 throw new RuntimeException("Package manager has died", e);
1797 }
1798 }
1799
1800 @Override
1801 public ApplicationInfo getApplicationInfo(String packageName, int flags)
1802 throws NameNotFoundException {
1803 try {
1804 ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
1805 if (ai != null) {
1806 return ai;
1807 }
1808 } catch (RemoteException e) {
1809 throw new RuntimeException("Package manager has died", e);
1810 }
1811
1812 throw new NameNotFoundException(packageName);
1813 }
1814
1815 @Override
1816 public ActivityInfo getActivityInfo(ComponentName className, int flags)
1817 throws NameNotFoundException {
1818 try {
1819 ActivityInfo ai = mPM.getActivityInfo(className, flags);
1820 if (ai != null) {
1821 return ai;
1822 }
1823 } catch (RemoteException e) {
1824 throw new RuntimeException("Package manager has died", e);
1825 }
1826
1827 throw new NameNotFoundException(className.toString());
1828 }
1829
1830 @Override
1831 public ActivityInfo getReceiverInfo(ComponentName className, int flags)
1832 throws NameNotFoundException {
1833 try {
1834 ActivityInfo ai = mPM.getReceiverInfo(className, flags);
1835 if (ai != null) {
1836 return ai;
1837 }
1838 } catch (RemoteException e) {
1839 throw new RuntimeException("Package manager has died", e);
1840 }
1841
1842 throw new NameNotFoundException(className.toString());
1843 }
1844
1845 @Override
1846 public ServiceInfo getServiceInfo(ComponentName className, int flags)
1847 throws NameNotFoundException {
1848 try {
1849 ServiceInfo si = mPM.getServiceInfo(className, flags);
1850 if (si != null) {
1851 return si;
1852 }
1853 } catch (RemoteException e) {
1854 throw new RuntimeException("Package manager has died", e);
1855 }
1856
1857 throw new NameNotFoundException(className.toString());
1858 }
1859
1860 @Override
Dianne Hackborn361199b2010-08-30 17:42:07 -07001861 public ProviderInfo getProviderInfo(ComponentName className, int flags)
1862 throws NameNotFoundException {
1863 try {
1864 ProviderInfo pi = mPM.getProviderInfo(className, flags);
1865 if (pi != null) {
1866 return pi;
1867 }
1868 } catch (RemoteException e) {
1869 throw new RuntimeException("Package manager has died", e);
1870 }
1871
1872 throw new NameNotFoundException(className.toString());
1873 }
1874
1875 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 public String[] getSystemSharedLibraryNames() {
1877 try {
1878 return mPM.getSystemSharedLibraryNames();
1879 } catch (RemoteException e) {
1880 throw new RuntimeException("Package manager has died", e);
1881 }
1882 }
1883
1884 @Override
Dianne Hackborn49237342009-08-27 20:08:01 -07001885 public FeatureInfo[] getSystemAvailableFeatures() {
1886 try {
1887 return mPM.getSystemAvailableFeatures();
1888 } catch (RemoteException e) {
1889 throw new RuntimeException("Package manager has died", e);
1890 }
1891 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001892
Dianne Hackborn49237342009-08-27 20:08:01 -07001893 @Override
Dianne Hackborn039c68e2009-09-26 16:39:23 -07001894 public boolean hasSystemFeature(String name) {
1895 try {
1896 return mPM.hasSystemFeature(name);
1897 } catch (RemoteException e) {
1898 throw new RuntimeException("Package manager has died", e);
1899 }
1900 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001901
Dianne Hackborn039c68e2009-09-26 16:39:23 -07001902 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 public int checkPermission(String permName, String pkgName) {
1904 try {
1905 return mPM.checkPermission(permName, pkgName);
1906 } catch (RemoteException e) {
1907 throw new RuntimeException("Package manager has died", e);
1908 }
1909 }
1910
1911 @Override
1912 public boolean addPermission(PermissionInfo info) {
1913 try {
1914 return mPM.addPermission(info);
1915 } catch (RemoteException e) {
1916 throw new RuntimeException("Package manager has died", e);
1917 }
1918 }
1919
1920 @Override
Dianne Hackbornd7c09682010-03-30 10:42:20 -07001921 public boolean addPermissionAsync(PermissionInfo info) {
1922 try {
1923 return mPM.addPermissionAsync(info);
1924 } catch (RemoteException e) {
1925 throw new RuntimeException("Package manager has died", e);
1926 }
1927 }
1928
1929 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 public void removePermission(String name) {
1931 try {
1932 mPM.removePermission(name);
1933 } catch (RemoteException e) {
1934 throw new RuntimeException("Package manager has died", e);
1935 }
1936 }
1937
1938 @Override
1939 public int checkSignatures(String pkg1, String pkg2) {
1940 try {
1941 return mPM.checkSignatures(pkg1, pkg2);
1942 } catch (RemoteException e) {
1943 throw new RuntimeException("Package manager has died", e);
1944 }
1945 }
1946
1947 @Override
Dianne Hackborn766cbfe2009-08-12 18:33:39 -07001948 public int checkSignatures(int uid1, int uid2) {
1949 try {
1950 return mPM.checkUidSignatures(uid1, uid2);
1951 } catch (RemoteException e) {
1952 throw new RuntimeException("Package manager has died", e);
1953 }
1954 }
1955
1956 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 public String[] getPackagesForUid(int uid) {
1958 try {
1959 return mPM.getPackagesForUid(uid);
1960 } catch (RemoteException e) {
1961 throw new RuntimeException("Package manager has died", e);
1962 }
1963 }
1964
1965 @Override
1966 public String getNameForUid(int uid) {
1967 try {
1968 return mPM.getNameForUid(uid);
1969 } catch (RemoteException e) {
1970 throw new RuntimeException("Package manager has died", e);
1971 }
1972 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001973
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 @Override
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02001975 public int getUidForSharedUser(String sharedUserName)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 throws NameNotFoundException {
1977 try {
1978 int uid = mPM.getUidForSharedUser(sharedUserName);
1979 if(uid != -1) {
1980 return uid;
1981 }
1982 } catch (RemoteException e) {
1983 throw new RuntimeException("Package manager has died", e);
1984 }
1985 throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
1986 }
1987
1988 @Override
1989 public List<PackageInfo> getInstalledPackages(int flags) {
1990 try {
1991 return mPM.getInstalledPackages(flags);
1992 } catch (RemoteException e) {
1993 throw new RuntimeException("Package manager has died", e);
1994 }
1995 }
1996
1997 @Override
1998 public List<ApplicationInfo> getInstalledApplications(int flags) {
1999 try {
2000 return mPM.getInstalledApplications(flags);
2001 } catch (RemoteException e) {
2002 throw new RuntimeException("Package manager has died", e);
2003 }
2004 }
2005
2006 @Override
2007 public ResolveInfo resolveActivity(Intent intent, int flags) {
2008 try {
2009 return mPM.resolveIntent(
2010 intent,
2011 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2012 flags);
2013 } catch (RemoteException e) {
2014 throw new RuntimeException("Package manager has died", e);
2015 }
2016 }
2017
2018 @Override
2019 public List<ResolveInfo> queryIntentActivities(Intent intent,
2020 int flags) {
2021 try {
2022 return mPM.queryIntentActivities(
2023 intent,
2024 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2025 flags);
2026 } catch (RemoteException e) {
2027 throw new RuntimeException("Package manager has died", e);
2028 }
2029 }
2030
2031 @Override
2032 public List<ResolveInfo> queryIntentActivityOptions(
2033 ComponentName caller, Intent[] specifics, Intent intent,
2034 int flags) {
2035 final ContentResolver resolver = mContext.getContentResolver();
2036
2037 String[] specificTypes = null;
2038 if (specifics != null) {
2039 final int N = specifics.length;
2040 for (int i=0; i<N; i++) {
2041 Intent sp = specifics[i];
2042 if (sp != null) {
2043 String t = sp.resolveTypeIfNeeded(resolver);
2044 if (t != null) {
2045 if (specificTypes == null) {
2046 specificTypes = new String[N];
2047 }
2048 specificTypes[i] = t;
2049 }
2050 }
2051 }
2052 }
2053
2054 try {
2055 return mPM.queryIntentActivityOptions(caller, specifics,
2056 specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
2057 flags);
2058 } catch (RemoteException e) {
2059 throw new RuntimeException("Package manager has died", e);
2060 }
2061 }
2062
2063 @Override
2064 public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
2065 try {
2066 return mPM.queryIntentReceivers(
2067 intent,
2068 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2069 flags);
2070 } catch (RemoteException e) {
2071 throw new RuntimeException("Package manager has died", e);
2072 }
2073 }
2074
2075 @Override
2076 public ResolveInfo resolveService(Intent intent, int flags) {
2077 try {
2078 return mPM.resolveService(
2079 intent,
2080 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2081 flags);
2082 } catch (RemoteException e) {
2083 throw new RuntimeException("Package manager has died", e);
2084 }
2085 }
2086
2087 @Override
2088 public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
2089 try {
2090 return mPM.queryIntentServices(
2091 intent,
2092 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2093 flags);
2094 } catch (RemoteException e) {
2095 throw new RuntimeException("Package manager has died", e);
2096 }
2097 }
2098
2099 @Override
2100 public ProviderInfo resolveContentProvider(String name,
2101 int flags) {
2102 try {
2103 return mPM.resolveContentProvider(name, flags);
2104 } catch (RemoteException e) {
2105 throw new RuntimeException("Package manager has died", e);
2106 }
2107 }
2108
2109 @Override
2110 public List<ProviderInfo> queryContentProviders(String processName,
2111 int uid, int flags) {
2112 try {
2113 return mPM.queryContentProviders(processName, uid, flags);
2114 } catch (RemoteException e) {
2115 throw new RuntimeException("Package manager has died", e);
2116 }
2117 }
2118
2119 @Override
2120 public InstrumentationInfo getInstrumentationInfo(
2121 ComponentName className, int flags)
2122 throws NameNotFoundException {
2123 try {
2124 InstrumentationInfo ii = mPM.getInstrumentationInfo(
2125 className, flags);
2126 if (ii != null) {
2127 return ii;
2128 }
2129 } catch (RemoteException e) {
2130 throw new RuntimeException("Package manager has died", e);
2131 }
2132
2133 throw new NameNotFoundException(className.toString());
2134 }
2135
2136 @Override
2137 public List<InstrumentationInfo> queryInstrumentation(
2138 String targetPackage, int flags) {
2139 try {
2140 return mPM.queryInstrumentation(targetPackage, flags);
2141 } catch (RemoteException e) {
2142 throw new RuntimeException("Package manager has died", e);
2143 }
2144 }
2145
2146 @Override public Drawable getDrawable(String packageName, int resid,
2147 ApplicationInfo appInfo) {
2148 ResourceName name = new ResourceName(packageName, resid);
2149 Drawable dr = getCachedIcon(name);
2150 if (dr != null) {
2151 return dr;
2152 }
2153 if (appInfo == null) {
2154 try {
2155 appInfo = getApplicationInfo(packageName, 0);
2156 } catch (NameNotFoundException e) {
2157 return null;
2158 }
2159 }
2160 try {
2161 Resources r = getResourcesForApplication(appInfo);
2162 dr = r.getDrawable(resid);
Dianne Hackborn11ea3342009-07-22 21:48:55 -07002163 if (false) {
2164 RuntimeException e = new RuntimeException("here");
2165 e.fillInStackTrace();
2166 Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
2167 + " from package " + packageName
2168 + ": app scale=" + r.getCompatibilityInfo().applicationScale
2169 + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
2170 e);
2171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
2173 + Integer.toHexString(resid) + " from " + r
2174 + ": " + dr);
2175 putCachedIcon(name, dr);
2176 return dr;
2177 } catch (NameNotFoundException e) {
2178 Log.w("PackageManager", "Failure retrieving resources for"
2179 + appInfo.packageName);
2180 } catch (RuntimeException e) {
2181 // If an exception was thrown, fall through to return
2182 // default icon.
2183 Log.w("PackageManager", "Failure retrieving icon 0x"
2184 + Integer.toHexString(resid) + " in package "
2185 + packageName, e);
2186 }
2187 return null;
2188 }
2189
2190 @Override public Drawable getActivityIcon(ComponentName activityName)
2191 throws NameNotFoundException {
2192 return getActivityInfo(activityName, 0).loadIcon(this);
2193 }
2194
2195 @Override public Drawable getActivityIcon(Intent intent)
2196 throws NameNotFoundException {
2197 if (intent.getComponent() != null) {
2198 return getActivityIcon(intent.getComponent());
2199 }
2200
2201 ResolveInfo info = resolveActivity(
2202 intent, PackageManager.MATCH_DEFAULT_ONLY);
2203 if (info != null) {
2204 return info.activityInfo.loadIcon(this);
2205 }
2206
2207 throw new NameNotFoundException(intent.toURI());
2208 }
2209
2210 @Override public Drawable getDefaultActivityIcon() {
2211 return Resources.getSystem().getDrawable(
2212 com.android.internal.R.drawable.sym_def_app_icon);
2213 }
2214
2215 @Override public Drawable getApplicationIcon(ApplicationInfo info) {
Jeff Brown07330792010-03-30 19:57:08 -07002216 return info.loadIcon(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002217 }
2218
2219 @Override public Drawable getApplicationIcon(String packageName)
2220 throws NameNotFoundException {
2221 return getApplicationIcon(getApplicationInfo(packageName, 0));
2222 }
Adam Powell81cd2e92010-04-21 16:35:18 -07002223
2224 @Override
2225 public Drawable getActivityLogo(ComponentName activityName)
2226 throws NameNotFoundException {
2227 return getActivityInfo(activityName, 0).loadLogo(this);
2228 }
2229
2230 @Override
2231 public Drawable getActivityLogo(Intent intent)
2232 throws NameNotFoundException {
2233 if (intent.getComponent() != null) {
2234 return getActivityLogo(intent.getComponent());
2235 }
2236
2237 ResolveInfo info = resolveActivity(
2238 intent, PackageManager.MATCH_DEFAULT_ONLY);
2239 if (info != null) {
2240 return info.activityInfo.loadLogo(this);
2241 }
2242
2243 throw new NameNotFoundException(intent.toUri(0));
2244 }
2245
2246 @Override
2247 public Drawable getApplicationLogo(ApplicationInfo info) {
2248 return info.loadLogo(this);
2249 }
2250
2251 @Override
2252 public Drawable getApplicationLogo(String packageName)
2253 throws NameNotFoundException {
2254 return getApplicationLogo(getApplicationInfo(packageName, 0));
2255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002256
2257 @Override public Resources getResourcesForActivity(
2258 ComponentName activityName) throws NameNotFoundException {
2259 return getResourcesForApplication(
2260 getActivityInfo(activityName, 0).applicationInfo);
2261 }
2262
2263 @Override public Resources getResourcesForApplication(
2264 ApplicationInfo app) throws NameNotFoundException {
2265 if (app.packageName.equals("system")) {
2266 return mContext.mMainThread.getSystemContext().getResources();
2267 }
2268 Resources r = mContext.mMainThread.getTopLevelResources(
2269 app.uid == Process.myUid() ? app.sourceDir
Dianne Hackborn11ea3342009-07-22 21:48:55 -07002270 : app.publicSourceDir, mContext.mPackageInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 if (r != null) {
2272 return r;
2273 }
2274 throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
2275 }
2276
2277 @Override public Resources getResourcesForApplication(
2278 String appPackageName) throws NameNotFoundException {
2279 return getResourcesForApplication(
2280 getApplicationInfo(appPackageName, 0));
2281 }
2282
2283 int mCachedSafeMode = -1;
2284 @Override public boolean isSafeMode() {
2285 try {
2286 if (mCachedSafeMode < 0) {
2287 mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
2288 }
2289 return mCachedSafeMode != 0;
2290 } catch (RemoteException e) {
2291 throw new RuntimeException("Package manager has died", e);
2292 }
2293 }
2294
2295 static void configurationChanged() {
2296 synchronized (sSync) {
2297 sIconCache.clear();
2298 sStringCache.clear();
2299 }
2300 }
2301
Dianne Hackborn21556372010-02-04 16:34:40 -08002302 ApplicationPackageManager(ContextImpl context,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 IPackageManager pm) {
2304 mContext = context;
2305 mPM = pm;
2306 }
2307
2308 private Drawable getCachedIcon(ResourceName name) {
2309 synchronized (sSync) {
2310 WeakReference<Drawable> wr = sIconCache.get(name);
2311 if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
2312 + name + ": " + wr);
2313 if (wr != null) { // we have the activity
2314 Drawable dr = wr.get();
2315 if (dr != null) {
2316 if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
2317 + name + ": " + dr);
2318 return dr;
2319 }
2320 // our entry has been purged
2321 sIconCache.remove(name);
2322 }
2323 }
2324 return null;
2325 }
2326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 private void putCachedIcon(ResourceName name, Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002328 synchronized (sSync) {
2329 sIconCache.put(name, new WeakReference<Drawable>(dr));
2330 if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
2331 + name + ": " + dr);
2332 }
2333 }
2334
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002335 static final void handlePackageBroadcast(int cmd, String[] pkgList,
2336 boolean hasPkgInfo) {
2337 boolean immediateGc = false;
2338 if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
2339 immediateGc = true;
2340 }
2341 if (pkgList != null && (pkgList.length > 0)) {
2342 boolean needCleanup = false;
2343 for (String ssp : pkgList) {
2344 synchronized (sSync) {
2345 if (sIconCache.size() > 0) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002346 Iterator<ResourceName> it = sIconCache.keySet().iterator();
2347 while (it.hasNext()) {
2348 ResourceName nm = it.next();
2349 if (nm.packageName.equals(ssp)) {
2350 //Log.i(TAG, "Removing cached drawable for " + nm);
2351 it.remove();
2352 needCleanup = true;
2353 }
2354 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002355 }
2356 if (sStringCache.size() > 0) {
2357 Iterator<ResourceName> it = sStringCache.keySet().iterator();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002358 while (it.hasNext()) {
2359 ResourceName nm = it.next();
2360 if (nm.packageName.equals(ssp)) {
2361 //Log.i(TAG, "Removing cached string for " + nm);
2362 it.remove();
2363 needCleanup = true;
2364 }
2365 }
2366 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08002367 }
Dianne Hackborn4416c3d2010-05-04 17:22:49 -07002368 }
2369 if (needCleanup || hasPkgInfo) {
2370 if (immediateGc) {
2371 // Schedule an immediate gc.
2372 Runtime.getRuntime().gc();
2373 } else {
2374 ActivityThread.currentActivityThread().scheduleGcIdler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002375 }
2376 }
2377 }
2378 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002380 private static final class ResourceName {
2381 final String packageName;
2382 final int iconId;
2383
2384 ResourceName(String _packageName, int _iconId) {
2385 packageName = _packageName;
2386 iconId = _iconId;
2387 }
2388
2389 ResourceName(ApplicationInfo aInfo, int _iconId) {
2390 this(aInfo.packageName, _iconId);
2391 }
2392
2393 ResourceName(ComponentInfo cInfo, int _iconId) {
2394 this(cInfo.applicationInfo.packageName, _iconId);
2395 }
2396
2397 ResourceName(ResolveInfo rInfo, int _iconId) {
2398 this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
2399 }
2400
2401 @Override
2402 public boolean equals(Object o) {
2403 if (this == o) return true;
2404 if (o == null || getClass() != o.getClass()) return false;
2405
2406 ResourceName that = (ResourceName) o;
2407
2408 if (iconId != that.iconId) return false;
2409 return !(packageName != null ?
2410 !packageName.equals(that.packageName) : that.packageName != null);
2411
2412 }
2413
2414 @Override
2415 public int hashCode() {
2416 int result;
2417 result = packageName.hashCode();
2418 result = 31 * result + iconId;
2419 return result;
2420 }
2421
2422 @Override
2423 public String toString() {
2424 return "{ResourceName " + packageName + " / " + iconId + "}";
2425 }
2426 }
2427
2428 private CharSequence getCachedString(ResourceName name) {
2429 synchronized (sSync) {
2430 WeakReference<CharSequence> wr = sStringCache.get(name);
2431 if (wr != null) { // we have the activity
2432 CharSequence cs = wr.get();
2433 if (cs != null) {
2434 return cs;
2435 }
2436 // our entry has been purged
2437 sStringCache.remove(name);
2438 }
2439 }
2440 return null;
2441 }
2442
2443 private void putCachedString(ResourceName name, CharSequence cs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002444 synchronized (sSync) {
2445 sStringCache.put(name, new WeakReference<CharSequence>(cs));
2446 }
2447 }
2448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002449 @Override
2450 public CharSequence getText(String packageName, int resid,
2451 ApplicationInfo appInfo) {
2452 ResourceName name = new ResourceName(packageName, resid);
2453 CharSequence text = getCachedString(name);
2454 if (text != null) {
2455 return text;
2456 }
2457 if (appInfo == null) {
2458 try {
2459 appInfo = getApplicationInfo(packageName, 0);
2460 } catch (NameNotFoundException e) {
2461 return null;
2462 }
2463 }
2464 try {
2465 Resources r = getResourcesForApplication(appInfo);
2466 text = r.getText(resid);
2467 putCachedString(name, text);
2468 return text;
2469 } catch (NameNotFoundException e) {
2470 Log.w("PackageManager", "Failure retrieving resources for"
2471 + appInfo.packageName);
2472 } catch (RuntimeException e) {
2473 // If an exception was thrown, fall through to return
2474 // default icon.
2475 Log.w("PackageManager", "Failure retrieving text 0x"
2476 + Integer.toHexString(resid) + " in package "
2477 + packageName, e);
2478 }
2479 return null;
2480 }
2481
2482 @Override
2483 public XmlResourceParser getXml(String packageName, int resid,
2484 ApplicationInfo appInfo) {
2485 if (appInfo == null) {
2486 try {
2487 appInfo = getApplicationInfo(packageName, 0);
2488 } catch (NameNotFoundException e) {
2489 return null;
2490 }
2491 }
2492 try {
2493 Resources r = getResourcesForApplication(appInfo);
2494 return r.getXml(resid);
2495 } catch (RuntimeException e) {
2496 // If an exception was thrown, fall through to return
2497 // default icon.
2498 Log.w("PackageManager", "Failure retrieving xml 0x"
2499 + Integer.toHexString(resid) + " in package "
2500 + packageName, e);
2501 } catch (NameNotFoundException e) {
2502 Log.w("PackageManager", "Failure retrieving resources for"
2503 + appInfo.packageName);
2504 }
2505 return null;
2506 }
2507
2508 @Override
2509 public CharSequence getApplicationLabel(ApplicationInfo info) {
Jeff Brown07330792010-03-30 19:57:08 -07002510 return info.loadLabel(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002511 }
2512
2513 @Override
Jacek Surazski65e13172009-04-28 15:26:38 +02002514 public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
2515 String installerPackageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 try {
Jacek Surazski65e13172009-04-28 15:26:38 +02002517 mPM.installPackage(packageURI, observer, flags, installerPackageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 } catch (RemoteException e) {
2519 // Should never happen!
2520 }
2521 }
2522
2523 @Override
Suchi Amalapurapu8946dd32010-02-19 09:19:34 -08002524 public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
2525 try {
2526 mPM.movePackage(packageName, observer, flags);
2527 } catch (RemoteException e) {
2528 // Should never happen!
2529 }
2530 }
2531
2532 @Override
Jacek Surazski65e13172009-04-28 15:26:38 +02002533 public String getInstallerPackageName(String packageName) {
2534 try {
2535 return mPM.getInstallerPackageName(packageName);
2536 } catch (RemoteException e) {
2537 // Should never happen!
2538 }
2539 return null;
2540 }
2541
2542 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002543 public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
2544 try {
2545 mPM.deletePackage(packageName, observer, flags);
2546 } catch (RemoteException e) {
2547 // Should never happen!
2548 }
2549 }
2550 @Override
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002551 public void clearApplicationUserData(String packageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002552 IPackageDataObserver observer) {
2553 try {
2554 mPM.clearApplicationUserData(packageName, observer);
2555 } catch (RemoteException e) {
2556 // Should never happen!
2557 }
2558 }
2559 @Override
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002560 public void deleteApplicationCacheFiles(String packageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 IPackageDataObserver observer) {
2562 try {
2563 mPM.deleteApplicationCacheFiles(packageName, observer);
2564 } catch (RemoteException e) {
2565 // Should never happen!
2566 }
2567 }
2568 @Override
2569 public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
2570 try {
2571 mPM.freeStorageAndNotify(idealStorageSize, observer);
2572 } catch (RemoteException e) {
2573 // Should never happen!
2574 }
2575 }
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -07002576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002577 @Override
Suchi Amalapurapubc806f62009-06-17 15:18:19 -07002578 public void freeStorage(long freeStorageSize, IntentSender pi) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 try {
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -07002580 mPM.freeStorage(freeStorageSize, pi);
2581 } catch (RemoteException e) {
2582 // Should never happen!
2583 }
2584 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 @Override
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002587 public void getPackageSizeInfo(String packageName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588 IPackageStatsObserver observer) {
2589 try {
2590 mPM.getPackageSizeInfo(packageName, observer);
2591 } catch (RemoteException e) {
2592 // Should never happen!
2593 }
2594 }
2595 @Override
2596 public void addPackageToPreferred(String packageName) {
2597 try {
2598 mPM.addPackageToPreferred(packageName);
2599 } catch (RemoteException e) {
2600 // Should never happen!
2601 }
2602 }
2603
2604 @Override
2605 public void removePackageFromPreferred(String packageName) {
2606 try {
2607 mPM.removePackageFromPreferred(packageName);
2608 } catch (RemoteException e) {
2609 // Should never happen!
2610 }
2611 }
2612
2613 @Override
2614 public List<PackageInfo> getPreferredPackages(int flags) {
2615 try {
2616 return mPM.getPreferredPackages(flags);
2617 } catch (RemoteException e) {
2618 // Should never happen!
2619 }
2620 return new ArrayList<PackageInfo>();
2621 }
2622
2623 @Override
2624 public void addPreferredActivity(IntentFilter filter,
2625 int match, ComponentName[] set, ComponentName activity) {
2626 try {
2627 mPM.addPreferredActivity(filter, match, set, activity);
2628 } catch (RemoteException e) {
2629 // Should never happen!
2630 }
2631 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 @Override
Satish Sampath8dbe6122009-06-02 23:35:54 +01002634 public void replacePreferredActivity(IntentFilter filter,
2635 int match, ComponentName[] set, ComponentName activity) {
2636 try {
2637 mPM.replacePreferredActivity(filter, match, set, activity);
2638 } catch (RemoteException e) {
2639 // Should never happen!
2640 }
2641 }
2642
2643 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 public void clearPackagePreferredActivities(String packageName) {
2645 try {
2646 mPM.clearPackagePreferredActivities(packageName);
2647 } catch (RemoteException e) {
2648 // Should never happen!
2649 }
2650 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 @Override
2653 public int getPreferredActivities(List<IntentFilter> outFilters,
2654 List<ComponentName> outActivities, String packageName) {
2655 try {
2656 return mPM.getPreferredActivities(outFilters, outActivities, packageName);
2657 } catch (RemoteException e) {
2658 // Should never happen!
2659 }
2660 return 0;
2661 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 @Override
2664 public void setComponentEnabledSetting(ComponentName componentName,
2665 int newState, int flags) {
2666 try {
2667 mPM.setComponentEnabledSetting(componentName, newState, flags);
2668 } catch (RemoteException e) {
2669 // Should never happen!
2670 }
2671 }
2672
2673 @Override
2674 public int getComponentEnabledSetting(ComponentName componentName) {
2675 try {
2676 return mPM.getComponentEnabledSetting(componentName);
2677 } catch (RemoteException e) {
2678 // Should never happen!
2679 }
2680 return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2681 }
2682
2683 @Override
2684 public void setApplicationEnabledSetting(String packageName,
2685 int newState, int flags) {
2686 try {
2687 mPM.setApplicationEnabledSetting(packageName, newState, flags);
2688 } catch (RemoteException e) {
2689 // Should never happen!
2690 }
2691 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002693 @Override
2694 public int getApplicationEnabledSetting(String packageName) {
2695 try {
2696 return mPM.getApplicationEnabledSetting(packageName);
2697 } catch (RemoteException e) {
2698 // Should never happen!
2699 }
2700 return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2701 }
2702
Kenny Root93565c42010-06-18 15:46:06 -07002703 @Override
2704 public void setPackageObbPath(String packageName, String path) {
2705 try {
2706 mPM.setPackageObbPath(packageName, path);
2707 } catch (RemoteException e) {
2708 // Should never happen!
2709 }
2710 }
2711
Dianne Hackborn21556372010-02-04 16:34:40 -08002712 private final ContextImpl mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002713 private final IPackageManager mPM;
2714
2715 private static final Object sSync = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002716 private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
2717 = new HashMap<ResourceName, WeakReference<Drawable> >();
2718 private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
2719 = new HashMap<ResourceName, WeakReference<CharSequence> >();
2720 }
2721
2722 // ----------------------------------------------------------------------
2723 // ----------------------------------------------------------------------
2724 // ----------------------------------------------------------------------
2725
2726 private static final class SharedPreferencesImpl implements SharedPreferences {
2727
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002728 // Lock ordering rules:
2729 // - acquire SharedPreferencesImpl.this before EditorImpl.this
2730 // - acquire mWritingToDiskLock before EditorImpl.this
2731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002732 private final File mFile;
2733 private final File mBackupFile;
2734 private final int mMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002736 private Map<String, Object> mMap; // guarded by 'this'
2737 private long mTimestamp; // guarded by 'this'
2738 private int mDiskWritesInFlight = 0; // guarded by 'this'
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002739 private boolean mLoaded = false; // guarded by 'this'
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002740
2741 private final Object mWritingToDiskLock = new Object();
The Android Open Source Project10592532009-03-18 17:39:46 -07002742 private static final Object mContent = new Object();
2743 private WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744
2745 SharedPreferencesImpl(
2746 File file, int mode, Map initialContents) {
2747 mFile = file;
2748 mBackupFile = makeBackupFile(file);
2749 mMode = mode;
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002750 mLoaded = initialContents != null;
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002751 mMap = initialContents != null ? initialContents : new HashMap<String, Object>();
2752 FileStatus stat = new FileStatus();
2753 if (FileUtils.getFileStatus(file.getPath(), stat)) {
2754 mTimestamp = stat.mtime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002755 }
The Android Open Source Project10592532009-03-18 17:39:46 -07002756 mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 }
2758
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002759 // Has this SharedPreferences ever had values assigned to it?
2760 boolean isLoaded() {
2761 synchronized (this) {
2762 return mLoaded;
2763 }
2764 }
2765
2766 // Has the file changed out from under us? i.e. writes that
2767 // we didn't instigate.
2768 public boolean hasFileChangedUnexpectedly() {
2769 synchronized (this) {
2770 if (mDiskWritesInFlight > 0) {
2771 // If we know we caused it, it's not unexpected.
2772 Log.d(TAG, "disk write in flight, not unexpected.");
2773 return false;
2774 }
2775 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002776 FileStatus stat = new FileStatus();
2777 if (!FileUtils.getFileStatus(mFile.getPath(), stat)) {
2778 return true;
2779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002780 synchronized (this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002781 return mTimestamp != stat.mtime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 }
2783 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002785 public void replace(Map newContents) {
Brad Fitzpatrick6194c532010-09-07 18:00:33 -07002786 synchronized (this) {
2787 mLoaded = true;
2788 if (newContents != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 mMap = newContents;
2790 }
2791 }
2792 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02002793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002794 public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2795 synchronized(this) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002796 mListeners.put(listener, mContent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002797 }
2798 }
2799
2800 public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2801 synchronized(this) {
2802 mListeners.remove(listener);
2803 }
2804 }
2805
2806 public Map<String, ?> getAll() {
2807 synchronized(this) {
2808 //noinspection unchecked
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002809 return new HashMap<String, Object>(mMap);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002810 }
2811 }
2812
2813 public String getString(String key, String defValue) {
2814 synchronized (this) {
2815 String v = (String)mMap.get(key);
2816 return v != null ? v : defValue;
2817 }
2818 }
Adam Powell212db7d2010-04-08 16:24:46 -07002819
2820 public Set<String> getStringSet(String key, Set<String> defValues) {
2821 synchronized (this) {
2822 Set<String> v = (Set<String>) mMap.get(key);
2823 return v != null ? v : defValues;
2824 }
2825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002826
2827 public int getInt(String key, int defValue) {
2828 synchronized (this) {
2829 Integer v = (Integer)mMap.get(key);
2830 return v != null ? v : defValue;
2831 }
2832 }
2833 public long getLong(String key, long defValue) {
2834 synchronized (this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002835 Long v = (Long)mMap.get(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836 return v != null ? v : defValue;
2837 }
2838 }
2839 public float getFloat(String key, float defValue) {
2840 synchronized (this) {
2841 Float v = (Float)mMap.get(key);
2842 return v != null ? v : defValue;
2843 }
2844 }
2845 public boolean getBoolean(String key, boolean defValue) {
2846 synchronized (this) {
2847 Boolean v = (Boolean)mMap.get(key);
2848 return v != null ? v : defValue;
2849 }
2850 }
2851
2852 public boolean contains(String key) {
2853 synchronized (this) {
2854 return mMap.containsKey(key);
2855 }
2856 }
2857
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002858 public Editor edit() {
2859 return new EditorImpl();
2860 }
2861
2862 // Return value from EditorImpl#commitToMemory()
2863 private static class MemoryCommitResult {
2864 public boolean changesMade; // any keys different?
2865 public List<String> keysModified; // may be null
2866 public Set<OnSharedPreferenceChangeListener> listeners; // may be null
2867 public Map<?, ?> mapToWriteToDisk;
2868 public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
2869 public volatile boolean writeToDiskResult = false;
2870
2871 public void setDiskWriteResult(boolean result) {
2872 writeToDiskResult = result;
2873 writtenToDiskLatch.countDown();
2874 }
2875 }
2876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 public final class EditorImpl implements Editor {
2878 private final Map<String, Object> mModified = Maps.newHashMap();
2879 private boolean mClear = false;
2880
2881 public Editor putString(String key, String value) {
2882 synchronized (this) {
2883 mModified.put(key, value);
2884 return this;
2885 }
2886 }
Adam Powell212db7d2010-04-08 16:24:46 -07002887 public Editor putStringSet(String key, Set<String> values) {
2888 synchronized (this) {
2889 mModified.put(key, values);
2890 return this;
2891 }
2892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002893 public Editor putInt(String key, int value) {
2894 synchronized (this) {
2895 mModified.put(key, value);
2896 return this;
2897 }
2898 }
2899 public Editor putLong(String key, long value) {
2900 synchronized (this) {
2901 mModified.put(key, value);
2902 return this;
2903 }
2904 }
2905 public Editor putFloat(String key, float value) {
2906 synchronized (this) {
2907 mModified.put(key, value);
2908 return this;
2909 }
2910 }
2911 public Editor putBoolean(String key, boolean value) {
2912 synchronized (this) {
2913 mModified.put(key, value);
2914 return this;
2915 }
2916 }
2917
2918 public Editor remove(String key) {
2919 synchronized (this) {
2920 mModified.put(key, this);
2921 return this;
2922 }
2923 }
2924
2925 public Editor clear() {
2926 synchronized (this) {
2927 mClear = true;
2928 return this;
2929 }
2930 }
2931
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07002932 public void apply() {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002933 final MemoryCommitResult mcr = commitToMemory();
2934 final Runnable awaitCommit = new Runnable() {
2935 public void run() {
2936 try {
2937 mcr.writtenToDiskLatch.await();
2938 } catch (InterruptedException ignored) {
2939 }
2940 }
2941 };
2942
2943 QueuedWork.add(awaitCommit);
2944
2945 Runnable postWriteRunnable = new Runnable() {
2946 public void run() {
2947 awaitCommit.run();
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002948 QueuedWork.remove(awaitCommit);
2949 }
2950 };
2951
2952 SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
2953
2954 // Okay to notify the listeners before it's hit disk
2955 // because the listeners should always get the same
2956 // SharedPreferences instance back, which has the
2957 // changes reflected in memory.
2958 notifyListeners(mcr);
Brad Fitzpatrickedf32d02010-08-25 13:13:36 -07002959 }
2960
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002961 // Returns true if any changes were made
2962 private MemoryCommitResult commitToMemory() {
2963 MemoryCommitResult mcr = new MemoryCommitResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 synchronized (SharedPreferencesImpl.this) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002965 // We optimistically don't make a deep copy until
2966 // a memory commit comes in when we're already
2967 // writing to disk.
2968 if (mDiskWritesInFlight > 0) {
2969 // We can't modify our mMap as a currently
2970 // in-flight write owns it. Clone it before
2971 // modifying it.
2972 // noinspection unchecked
2973 mMap = new HashMap<String, Object>(mMap);
2974 }
2975 mcr.mapToWriteToDisk = mMap;
2976 mDiskWritesInFlight++;
2977
2978 boolean hasListeners = mListeners.size() > 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 if (hasListeners) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002980 mcr.keysModified = new ArrayList<String>();
2981 mcr.listeners =
2982 new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 }
2984
2985 synchronized (this) {
2986 if (mClear) {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002987 if (!mMap.isEmpty()) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002988 mcr.changesMade = true;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002989 mMap.clear();
2990 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002991 mClear = false;
2992 }
2993
The Android Open Source Project10592532009-03-18 17:39:46 -07002994 for (Entry<String, Object> e : mModified.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 String k = e.getKey();
2996 Object v = e.getValue();
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07002997 if (v == this) { // magic value for a removal mutation
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07002998 if (!mMap.containsKey(k)) {
2999 continue;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003000 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003001 mMap.remove(k);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003002 } else {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003003 boolean isSame = false;
3004 if (mMap.containsKey(k)) {
3005 Object existingValue = mMap.get(k);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003006 if (existingValue != null && existingValue.equals(v)) {
3007 continue;
3008 }
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003009 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003010 mMap.put(k, v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003011 }
3012
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003013 mcr.changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003014 if (hasListeners) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003015 mcr.keysModified.add(k);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003016 }
3017 }
3018
3019 mModified.clear();
3020 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003021 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003022 return mcr;
3023 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003025 public boolean commit() {
3026 MemoryCommitResult mcr = commitToMemory();
3027 SharedPreferencesImpl.this.enqueueDiskWrite(
3028 mcr, null /* sync write on this thread okay */);
3029 try {
3030 mcr.writtenToDiskLatch.await();
3031 } catch (InterruptedException e) {
3032 return false;
3033 }
3034 notifyListeners(mcr);
3035 return mcr.writeToDiskResult;
3036 }
3037
3038 private void notifyListeners(final MemoryCommitResult mcr) {
3039 if (mcr.listeners == null || mcr.keysModified == null ||
3040 mcr.keysModified.size() == 0) {
3041 return;
3042 }
3043 if (Looper.myLooper() == Looper.getMainLooper()) {
3044 for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
3045 final String key = mcr.keysModified.get(i);
3046 for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
The Android Open Source Project10592532009-03-18 17:39:46 -07003047 if (listener != null) {
3048 listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
3049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003050 }
3051 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003052 } else {
3053 // Run this function on the main thread.
3054 ActivityThread.sMainThreadHandler.post(new Runnable() {
3055 public void run() {
3056 notifyListeners(mcr);
3057 }
3058 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 }
3061 }
3062
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003063 /**
3064 * Enqueue an already-committed-to-memory result to be written
3065 * to disk.
3066 *
3067 * They will be written to disk one-at-a-time in the order
3068 * that they're enqueued.
3069 *
3070 * @param postWriteRunnable if non-null, we're being called
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07003071 * from apply() and this is the runnable to run after
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003072 * the write proceeds. if null (from a regular commit()),
3073 * then we're allowed to do this disk write on the main
3074 * thread (which in addition to reducing allocations and
3075 * creating a background thread, this has the advantage that
3076 * we catch them in userdebug StrictMode reports to convert
Brad Fitzpatrick66fce502010-08-30 18:10:49 -07003077 * them where possible to apply() ...)
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003078 */
3079 private void enqueueDiskWrite(final MemoryCommitResult mcr,
3080 final Runnable postWriteRunnable) {
3081 final Runnable writeToDiskRunnable = new Runnable() {
3082 public void run() {
3083 synchronized (mWritingToDiskLock) {
3084 writeToFile(mcr);
3085 }
3086 synchronized (SharedPreferencesImpl.this) {
3087 mDiskWritesInFlight--;
3088 }
3089 if (postWriteRunnable != null) {
3090 postWriteRunnable.run();
3091 }
3092 }
3093 };
3094
3095 final boolean isFromSyncCommit = (postWriteRunnable == null);
3096
3097 // Typical #commit() path with fewer allocations, doing a write on
3098 // the current thread.
3099 if (isFromSyncCommit) {
3100 boolean wasEmpty = false;
3101 synchronized (SharedPreferencesImpl.this) {
3102 wasEmpty = mDiskWritesInFlight == 1;
3103 }
3104 if (wasEmpty) {
3105 writeToDiskRunnable.run();
3106 return;
3107 }
3108 }
3109
3110 QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003111 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02003112
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003113 private static FileOutputStream createFileOutputStream(File file) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003114 FileOutputStream str = null;
3115 try {
3116 str = new FileOutputStream(file);
3117 } catch (FileNotFoundException e) {
3118 File parent = file.getParentFile();
3119 if (!parent.mkdir()) {
3120 Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
3121 return null;
3122 }
3123 FileUtils.setPermissions(
3124 parent.getPath(),
3125 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
3126 -1, -1);
3127 try {
3128 str = new FileOutputStream(file);
3129 } catch (FileNotFoundException e2) {
3130 Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
3131 }
3132 }
3133 return str;
3134 }
3135
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003136 // Note: must hold mWritingToDiskLock
3137 private void writeToFile(MemoryCommitResult mcr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003138 // Rename the current file so it may be used as a backup during the next read
3139 if (mFile.exists()) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003140 if (!mcr.changesMade) {
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003141 // If the file already exists, but no changes were
3142 // made to the underlying map, it's wasteful to
3143 // re-write the file. Return as if we wrote it
3144 // out.
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003145 mcr.setDiskWriteResult(true);
3146 return;
Brad Fitzpatrick67fed012010-08-17 10:29:15 -07003147 }
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07003148 if (!mBackupFile.exists()) {
3149 if (!mFile.renameTo(mBackupFile)) {
3150 Log.e(TAG, "Couldn't rename file " + mFile
3151 + " to backup file " + mBackupFile);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003152 mcr.setDiskWriteResult(false);
3153 return;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07003154 }
3155 } else {
3156 mFile.delete();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
3158 }
Christian Mehlmauer5f5acca2010-06-25 19:06:18 +02003159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 // Attempt to write the file, delete the backup and return true as atomically as
3161 // possible. If any exception occurs, delete the new file; next time we will restore
3162 // from the backup.
3163 try {
3164 FileOutputStream str = createFileOutputStream(mFile);
3165 if (str == null) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003166 mcr.setDiskWriteResult(false);
3167 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003169 XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 str.close();
3171 setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003172 FileStatus stat = new FileStatus();
3173 if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
3174 synchronized (this) {
3175 mTimestamp = stat.mtime;
3176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 }
Dianne Hackborn51bf0772009-03-24 19:11:41 -07003178 // Writing was successful, delete the backup file if there is one.
3179 mBackupFile.delete();
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003180 mcr.setDiskWriteResult(true);
3181 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 } catch (XmlPullParserException e) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003183 Log.w(TAG, "writeToFile: Got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184 } catch (IOException e) {
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003185 Log.w(TAG, "writeToFile: Got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 }
3187 // Clean up an unsuccessfully written file
3188 if (mFile.exists()) {
3189 if (!mFile.delete()) {
3190 Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
3191 }
3192 }
Brad Fitzpatrick333b8cb2010-08-26 12:04:57 -07003193 mcr.setDiskWriteResult(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 }
3195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196}