diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
commit | f013e1afd1e68af5e3b868c26a653bbfb39538f8 (patch) | |
tree | 7ad6c8fd9c7b55f4b4017171dec1cb760bbd26bf /core/java/android/app | |
parent | e70cfafe580c6f2994c4827cd8a534aabf3eb05c (diff) | |
download | frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.zip frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.gz frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'core/java/android/app')
20 files changed, 770 insertions, 113 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index fa310a5..eafb048 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -62,6 +62,7 @@ import android.widget.AdapterView; import com.android.internal.policy.PolicyManager; import java.util.ArrayList; +import java.util.HashMap; /** * An activity is a single, focused thing that the user can do. Almost all @@ -613,7 +614,8 @@ public class Activity extends ContextThemeWrapper private ComponentName mComponent; /*package*/ ActivityInfo mActivityInfo; /*package*/ ActivityThread mMainThread; - private Object mLastNonConfigurationInstance; + /*package*/ Object mLastNonConfigurationInstance; + /*package*/ HashMap<String,Object> mLastNonConfigurationChildInstances; Activity mParent; boolean mCalled; private boolean mResumed; @@ -1379,6 +1381,38 @@ public class Activity extends ContextThemeWrapper return null; } + /** + * Retrieve the non-configuration instance data that was previously + * returned by {@link #onRetainNonConfigurationChildInstances()}. This will + * be available from the initial {@link #onCreate} and + * {@link #onStart} calls to the new instance, allowing you to extract + * any useful dynamic state from the previous instance. + * + * <p>Note that the data you retrieve here should <em>only</em> be used + * as an optimization for handling configuration changes. You should always + * be able to handle getting a null pointer back, and an activity must + * still be able to restore itself to its previous state (through the + * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this + * function returns null. + * + * @return Returns the object previously returned by + * {@link #onRetainNonConfigurationChildInstances()} + */ + HashMap<String,Object> getLastNonConfigurationChildInstances() { + return mLastNonConfigurationChildInstances; + } + + /** + * This method is similar to {@link #onRetainNonConfigurationInstance()} except that + * it should return either a mapping from child activity id strings to arbitrary objects, + * or null. This method is intended to be used by Activity framework subclasses that control a + * set of child activities, such as ActivityGroup. The same guarantees and restrictions apply + * as for {@link #onRetainNonConfigurationInstance()}. The default implementation returns null. + */ + HashMap<String,Object> onRetainNonConfigurationChildInstances() { + return null; + } + public void onLowMemory() { mCalled = true; } @@ -1837,13 +1871,50 @@ public class Activity extends ContextThemeWrapper * Called when the current {@link Window} of the activity gains or loses * focus. This is the best indicator of whether this activity is visible * to the user. + * + * <p>Note that this provides information what global focus state, which + * is managed independently of activity lifecycles. As such, while focus + * changes will generally have some relation to lifecycle changes (an + * activity that is stopped will not generally get window focus), you + * should not rely on any particular order between the callbacks here and + * those in the other lifecycle methods such as {@link #onResume}. + * + * <p>As a general rule, however, a resumed activity will have window + * focus... unless it has displayed other dialogs or popups that take + * input focus, in which case the activity itself will not have focus + * when the other windows have it. Likewise, the system may display + * system-level windows (such as the status bar notification panel or + * a system alert) which will temporarily take window input focus without + * pausing the foreground activity. * * @param hasFocus Whether the window of this activity has focus. + * + * @see #hasWindowFocus() + * @see #onResume */ public void onWindowFocusChanged(boolean hasFocus) { } /** + * Returns true if this activity's <em>main</em> window currently has window focus. + * Note that this is not the same as the view itself having focus. + * + * @return True if this activity's main window currently has window focus. + * + * @see #onWindowAttributesChanged(android.view.WindowManager.LayoutParams) + */ + public boolean hasWindowFocus() { + Window w = getWindow(); + if (w != null) { + View d = w.getDecorView(); + if (d != null) { + return d.hasWindowFocus(); + } + } + return false; + } + + /** * Called to process key events. You can override this to intercept all * key events before they are dispatched to the window. Be sure to call * this implementation for key events that should be handled normally. @@ -2160,6 +2231,15 @@ public class Activity extends ContextThemeWrapper } /** + * Programmatically closes the most recently opened context menu, if showing. + * + * @hide pending API council + */ + public void closeContextMenu() { + mWindow.closePanel(Window.FEATURE_CONTEXT_MENU); + } + + /** * This hook is called whenever an item in a context menu is selected. The * default implementation simply returns false to have the normal processing * happen (calling the item's Runnable or sending a message to its Handler @@ -2910,6 +2990,7 @@ public class Activity extends ContextThemeWrapper * @param flags May be {@link PendingIntent#FLAG_ONE_SHOT PendingIntent.FLAG_ONE_SHOT}, * {@link PendingIntent#FLAG_NO_CREATE PendingIntent.FLAG_NO_CREATE}, * {@link PendingIntent#FLAG_CANCEL_CURRENT PendingIntent.FLAG_CANCEL_CURRENT}, + * {@link PendingIntent#FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT}, * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. @@ -3285,10 +3366,21 @@ public class Activity extends ContextThemeWrapper Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance, Configuration config) { + attach(context, aThread, instr, token, application, intent, info, title, parent, id, + lastNonConfigurationInstance, null, config); + } + + final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, + Application application, Intent intent, ActivityInfo info, CharSequence title, + Activity parent, String id, Object lastNonConfigurationInstance, + HashMap<String,Object> lastNonConfigurationChildInstances, Configuration config) { attachBaseContext(context); mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); + if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { + mWindow.setSoftInputMode(info.softInputMode); + } mUiThread = Thread.currentThread(); mMainThread = aThread; @@ -3302,6 +3394,7 @@ public class Activity extends ContextThemeWrapper mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstance = lastNonConfigurationInstance; + mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances; mWindow.setWindowManager(null, mToken, mComponent.flattenToString()); if (mParent != null) { @@ -3375,6 +3468,10 @@ public class Activity extends ContextThemeWrapper } } + final void performPause() { + onPause(); + } + final void performStop() { if (!mStopped) { if (mWindow != null) { diff --git a/core/java/android/app/ActivityGroup.java b/core/java/android/app/ActivityGroup.java index 96bb475..f1216f9 100644 --- a/core/java/android/app/ActivityGroup.java +++ b/core/java/android/app/ActivityGroup.java @@ -16,14 +16,19 @@ package android.app; +import java.util.HashMap; + import android.content.Intent; import android.os.Bundle; +import android.util.Log; /** * A screen that contains and runs multiple embedded activities. */ public class ActivityGroup extends Activity { + private static final String TAG = "ActivityGroup"; private static final String STATES_KEY = "android:states"; + static final String PARENT_NON_CONFIG_INSTANCE_KEY = "android:parent_non_config_instance"; /** * This field should be made private, so it is hidden from the SDK. @@ -80,6 +85,17 @@ public class ActivityGroup extends Activity { mLocalActivityManager.dispatchDestroy(isFinishing()); } + /** + * Returns a HashMap mapping from child activity ids to the return values + * from calls to their onRetainNonConfigurationInstance methods. + * + * {@hide} + */ + @Override + public HashMap<String,Object> onRetainNonConfigurationChildInstances() { + return mLocalActivityManager.dispatchRetainNonConfigurationInstance(); + } + public Activity getCurrentActivity() { return mLocalActivityManager.getCurrentActivity(); } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 6eb1102..f9b9221 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -29,7 +29,6 @@ import android.os.Parcelable; import android.os.Parcelable.Creator; import android.text.TextUtils; import android.util.Log; - import java.util.List; /** @@ -601,4 +600,75 @@ public class ActivityManager { return null; } } + + /** + * Information you can retrieve about a running process. + */ + public static class RunningAppProcessInfo implements Parcelable { + /** + * The name of the process that this object is associated with + */ + public String processName; + + /** + * The pid of this process; 0 if none + */ + public int pid; + + public String pkgList[]; + + public RunningAppProcessInfo() { + } + + public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) { + processName = pProcessName; + pid = pPid; + pkgList = pArr; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(processName); + dest.writeInt(pid); + dest.writeStringArray(pkgList); + } + + public void readFromParcel(Parcel source) { + processName = source.readString(); + pid = source.readInt(); + pkgList = source.readStringArray(); + } + + public static final Creator<RunningAppProcessInfo> CREATOR = + new Creator<RunningAppProcessInfo>() { + public RunningAppProcessInfo createFromParcel(Parcel source) { + return new RunningAppProcessInfo(source); + } + public RunningAppProcessInfo[] newArray(int size) { + return new RunningAppProcessInfo[size]; + } + }; + + private RunningAppProcessInfo(Parcel source) { + readFromParcel(source); + } + } + + /** + * Returns a list of application processes that are running on the device. + * + * @return Returns a list of RunningAppProcessInfo records, or null if there are no + * running processes (it will not return an empty list). This list ordering is not + * specified. + */ + public List<RunningAppProcessInfo> getRunningAppProcesses() { + try { + return ActivityManagerNative.getDefault().getRunningAppProcesses(); + } catch (RemoteException e) { + return null; + } + } } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index e6f1b05..ae9f3bf 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -387,6 +387,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeTypedList(list); return true; } + + case GET_RUNNING_APP_PROCESSES_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + List<ActivityManager.RunningAppProcessInfo> list = getRunningAppProcesses(); + reply.writeNoException(); + reply.writeTypedList(list); + return true; + } case MOVE_TASK_TO_FRONT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); @@ -1314,6 +1322,19 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return list; } + public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(GET_RUNNING_APP_PROCESSES_TRANSACTION, data, reply, 0); + reply.readException(); + ArrayList<ActivityManager.RunningAppProcessInfo> list + = reply.createTypedArrayList(ActivityManager.RunningAppProcessInfo.CREATOR); + data.recycle(); + reply.recycle(); + return list; + } public void moveTaskToFront(int task) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d03a76f..3d448a6 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -220,7 +220,8 @@ public final class ActivityThread { mApplicationInfo = aInfo; mPackageName = aInfo.packageName; mAppDir = aInfo.sourceDir; - mResDir = aInfo.publicSourceDir; + mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir + : aInfo.publicSourceDir; mSharedLibraries = aInfo.sharedLibraryFiles; mDataDir = aInfo.dataDir; mDataDirFile = mDataDir != null ? new File(mDataDir) : null; @@ -1057,6 +1058,7 @@ public final class ActivityThread { Activity parent; String embeddedID; Object lastNonConfigurationInstance; + HashMap<String,Object> lastNonConfigurationChildInstances; boolean paused; boolean stopped; boolean hideForNow; @@ -1966,6 +1968,12 @@ public final class ActivityThread { public final Activity startActivityNow(Activity parent, String id, Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state) { + return startActivityNow(parent, id, intent, activityInfo, token, state, null); + } + + public final Activity startActivityNow(Activity parent, String id, + Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state, + Object lastNonConfigurationInstance) { ActivityRecord r = new ActivityRecord(); r.token = token; r.intent = intent; @@ -1973,6 +1981,7 @@ public final class ActivityThread { r.parent = parent; r.embeddedID = id; r.activityInfo = activityInfo; + r.lastNonConfigurationInstance = lastNonConfigurationInstance; if (localLOGV) { ComponentName compname = intent.getComponent(); String name; @@ -2090,9 +2099,11 @@ public final class ActivityThread { Configuration config = new Configuration(mConfiguration); activity.attach(appContext, this, getInstrumentation(), r.token, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, - r.lastNonConfigurationInstance, config); + r.lastNonConfigurationInstance, r.lastNonConfigurationChildInstances, + config); r.lastNonConfigurationInstance = null; + r.lastNonConfigurationChildInstances = null; activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { @@ -2948,6 +2959,17 @@ public final class ActivityThread { + ": " + e.toString(), e); } } + try { + r.lastNonConfigurationChildInstances + = r.activity.onRetainNonConfigurationChildInstances(); + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to retain child activities " + + r.intent.getComponent().toShortString() + + ": " + e.toString(), e); + } + } } try { @@ -3225,11 +3247,7 @@ public final class ActivityThread { Locale.setDefault(config.locale); } - if (mSystemContext != null) { - mSystemContext.getResources().updateConfiguration(config, null); - //Log.i(TAG, "Updated system resources " + mSystemContext.getResources() - // + ": " + mSystemContext.getResources().getConfiguration()); - } + Resources.updateSystemConfiguration(config, null); ApplicationContext.ApplicationPackageManager.configurationChanged(); //Log.i(TAG, "Configuration changed in " + currentPackageName()); diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index 35c6ac1..b4c0e31 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -71,17 +71,13 @@ public class AlarmManager */ public static final int ELAPSED_REALTIME = 3; - private static IAlarmManager mService; + private final IAlarmManager mService; - static { - mService = IAlarmManager.Stub.asInterface( - ServiceManager.getService(Context.ALARM_SERVICE)); - } - /** * package private on purpose */ - AlarmManager() { + AlarmManager(IAlarmManager service) { + mService = service; } /** @@ -97,7 +93,7 @@ public class AlarmManager * this one. * * <p> - * The alarm is an intent broadcast that goes to an intent receiver that + * The alarm is an intent broadcast that goes to a broadcast receiver that * you registered with {@link android.content.Context#registerReceiver} * or through the <receiver> tag in an AndroidManifest.xml file. * @@ -189,6 +185,72 @@ public class AlarmManager } /** + * Available inexact recurrence intervals recognized by + * {@link #setInexactRepeating(int, long, long, PendingIntent)} + */ + public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000; + public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES; + public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR; + public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR; + public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY; + + /** + * Schedule a repeating alarm that has inexact trigger time requirements; + * for example, an alarm that repeats every hour, but not necessarily at + * the top of every hour. These alarms are more power-efficient than + * the strict recurrences supplied by {@link #setRepeating}, since the + * system can adjust alarms' phase to cause them to fire simultaneously, + * avoiding waking the device from sleep more than necessary. + * + * <p>Your alarm's first trigger will not be before the requested time, + * but it might not occur for almost a full interval after that time. In + * addition, while the overall period of the repeating alarm will be as + * requested, the time between any two successive firings of the alarm + * may vary. If your application demands very low jitter, use + * {@link #setRepeating} instead. + * + * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or + * RTC_WAKEUP. + * @param triggerAtTime Time the alarm should first go off, using the + * appropriate clock (depending on the alarm type). This + * is inexact: the alarm will not fire before this time, + * but there may be a delay of almost an entire alarm + * interval before the first invocation of the alarm. + * @param interval Interval between subsequent repeats of the alarm. If + * this is one of INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, + * INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY then the + * alarm will be phase-aligned with other alarms to reduce + * the number of wakeups. Otherwise, the alarm will be set + * as though the application had called {@link #setRepeating}. + * @param operation Action to perform when the alarm goes off; + * typically comes from {@link PendingIntent#getBroadcast + * IntentSender.getBroadcast()}. + * + * @see android.os.Handler + * @see #set + * @see #cancel + * @see android.content.Context#sendBroadcast + * @see android.content.Context#registerReceiver + * @see android.content.Intent#filterEquals + * @see #ELAPSED_REALTIME + * @see #ELAPSED_REALTIME_WAKEUP + * @see #RTC + * @see #RTC_WAKEUP + * @see #INTERVAL_FIFTEEN_MINUTES + * @see #INTERVAL_HALF_HOUR + * @see #INTERVAL_HOUR + * @see #INTERVAL_HALF_DAY + * @see #INTERVAL_DAY + */ + public void setInexactRepeating(int type, long triggerAtTime, long interval, + PendingIntent operation) { + try { + mService.setInexactRepeating(type, triggerAtTime, interval, operation); + } catch (RemoteException ex) { + } + } + + /** * Remove any alarms with a matching {@link Intent}. * Any alarm, of any type, whose Intent matches this one (as defined by * {@link Intent#filterEquals}), will be canceled. diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index cc80ba4..a6981a5 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -25,6 +25,7 @@ import android.os.Message; import android.view.KeyEvent; import android.view.View; import android.widget.AdapterView; +import android.widget.Button; import android.widget.ListAdapter; import android.widget.ListView; @@ -59,6 +60,29 @@ public class AlertDialog extends Dialog implements DialogInterface { setOnCancelListener(cancelListener); mAlert = new AlertController(context, this, getWindow()); } + + /** + * Gets one of the buttons used in the dialog. + * <p> + * If a button does not exist in the dialog, null will be returned. + * + * @param whichButton The identifier of the button that should be returned. + * For example, this can be + * {@link DialogInterface#BUTTON_POSITIVE}. + * @return The button from the dialog, or null if a button does not exist. + */ + public Button getButton(int whichButton) { + return mAlert.getButton(whichButton); + } + + /** + * Gets the list view used in the dialog. + * + * @return The {@link ListView} from the dialog. + */ + public ListView getListView() { + return mAlert.getListView(); + } @Override public void setTitle(CharSequence title) { @@ -83,44 +107,115 @@ public class AlertDialog extends Dialog implements DialogInterface { public void setView(View view) { mAlert.setView(view); } + + /** + * Set the view to display in that dialog, specifying the spacing to appear around that + * view. + * + * @param view The view to show in the content area of the dialog + * @param viewSpacingLeft Extra space to appear to the left of {@code view} + * @param viewSpacingTop Extra space to appear above {@code view} + * @param viewSpacingRight Extra space to appear to the right of {@code view} + * @param viewSpacingBottom Extra space to appear below {@code view} + */ + public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, + int viewSpacingBottom) { + mAlert.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom); + } - public void setButton(CharSequence text, Message msg) { - mAlert.setButton(text, msg); + /** + * Set a message to be sent when a button is pressed. + * + * @param whichButton Which button to set the message for, can be one of + * {@link DialogInterface#BUTTON_POSITIVE}, + * {@link DialogInterface#BUTTON_NEGATIVE}, or + * {@link DialogInterface#BUTTON_NEUTRAL} + * @param text The text to display in positive button. + * @param msg The {@link Message} to be sent when clicked. + */ + public void setButton(int whichButton, CharSequence text, Message msg) { + mAlert.setButton(whichButton, text, null, msg); + } + + /** + * Set a listener to be invoked when the positive button of the dialog is pressed. + * + * @param whichButton Which button to set the listener on, can be one of + * {@link DialogInterface#BUTTON_POSITIVE}, + * {@link DialogInterface#BUTTON_NEGATIVE}, or + * {@link DialogInterface#BUTTON_NEUTRAL} + * @param text The text to display in positive button. + * @param listener The {@link DialogInterface.OnClickListener} to use. + */ + public void setButton(int whichButton, CharSequence text, OnClickListener listener) { + mAlert.setButton(whichButton, text, listener, null); } + /** + * @deprecated Use {@link #setButton(int, CharSequence, Message)} with + * {@link DialogInterface#BUTTON_POSITIVE}. + */ + @Deprecated + public void setButton(CharSequence text, Message msg) { + setButton(BUTTON_POSITIVE, text, msg); + } + + /** + * @deprecated Use {@link #setButton(int, CharSequence, Message)} with + * {@link DialogInterface#BUTTON_NEGATIVE}. + */ + @Deprecated public void setButton2(CharSequence text, Message msg) { - mAlert.setButton2(text, msg); + setButton(BUTTON_NEGATIVE, text, msg); } + /** + * @deprecated Use {@link #setButton(int, CharSequence, Message)} with + * {@link DialogInterface#BUTTON_NEUTRAL}. + */ + @Deprecated public void setButton3(CharSequence text, Message msg) { - mAlert.setButton3(text, msg); + setButton(BUTTON_NEUTRAL, text, msg); } /** * Set a listener to be invoked when button 1 of the dialog is pressed. + * * @param text The text to display in button 1. * @param listener The {@link DialogInterface.OnClickListener} to use. + * @deprecated Use + * {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)} + * with {@link DialogInterface#BUTTON_POSITIVE} */ + @Deprecated public void setButton(CharSequence text, final OnClickListener listener) { - mAlert.setButton(text, listener); + setButton(BUTTON_POSITIVE, text, listener); } /** * Set a listener to be invoked when button 2 of the dialog is pressed. * @param text The text to display in button 2. * @param listener The {@link DialogInterface.OnClickListener} to use. + * @deprecated Use + * {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)} + * with {@link DialogInterface#BUTTON_NEGATIVE} */ + @Deprecated public void setButton2(CharSequence text, final OnClickListener listener) { - mAlert.setButton2(text, listener); + setButton(BUTTON_NEGATIVE, text, listener); } /** * Set a listener to be invoked when button 3 of the dialog is pressed. * @param text The text to display in button 3. * @param listener The {@link DialogInterface.OnClickListener} to use. + * @deprecated Use + * {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)} + * with {@link DialogInterface#BUTTON_POSITIVE} */ + @Deprecated public void setButton3(CharSequence text, final OnClickListener listener) { - mAlert.setButton3(text, listener); + setButton(BUTTON_NEUTRAL, text, listener); } /** @@ -170,6 +265,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the title using the given resource id. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setTitle(int titleId) { P.mTitle = P.mContext.getText(titleId); @@ -178,6 +275,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the title displayed in the {@link Dialog}. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setTitle(CharSequence title) { P.mTitle = title; @@ -192,6 +291,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * via the other methods. * * @param customTitleView The custom view to use as the title. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setCustomTitle(View customTitleView) { P.mCustomTitleView = customTitleView; @@ -200,6 +301,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the message to display using the given resource id. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMessage(int messageId) { P.mMessage = P.mContext.getText(messageId); @@ -208,6 +311,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the message to display. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMessage(CharSequence message) { P.mMessage = message; @@ -216,6 +321,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the resource id of the {@link Drawable} to be used in the title. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setIcon(int iconId) { P.mIconId = iconId; @@ -224,6 +331,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set the {@link Drawable} to be used in the title. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setIcon(Drawable icon) { P.mIcon = icon; @@ -234,6 +343,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the positive button of the dialog is pressed. * @param textId The resource id of the text to display in the positive button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setPositiveButton(int textId, final OnClickListener listener) { P.mPositiveButtonText = P.mContext.getText(textId); @@ -245,6 +356,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the positive button of the dialog is pressed. * @param text The text to display in the positive button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setPositiveButton(CharSequence text, final OnClickListener listener) { P.mPositiveButtonText = text; @@ -256,6 +369,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the negative button of the dialog is pressed. * @param textId The resource id of the text to display in the negative button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNegativeButton(int textId, final OnClickListener listener) { P.mNegativeButtonText = P.mContext.getText(textId); @@ -267,6 +382,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the negative button of the dialog is pressed. * @param text The text to display in the negative button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNegativeButton(CharSequence text, final OnClickListener listener) { P.mNegativeButtonText = text; @@ -278,6 +395,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the neutral button of the dialog is pressed. * @param textId The resource id of the text to display in the neutral button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNeutralButton(int textId, final OnClickListener listener) { P.mNeutralButtonText = P.mContext.getText(textId); @@ -289,6 +408,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * Set a listener to be invoked when the neutral button of the dialog is pressed. * @param text The text to display in the neutral button * @param listener The {@link DialogInterface.OnClickListener} to use. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setNeutralButton(CharSequence text, final OnClickListener listener) { P.mNeutralButtonText = text; @@ -298,6 +419,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Sets whether the dialog is cancelable or not default is true. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setCancelable(boolean cancelable) { P.mCancelable = cancelable; @@ -307,6 +430,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Sets the callback that will be called if the dialog is canceled. * @see #setCancelable(boolean) + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnCancelListener(OnCancelListener onCancelListener) { P.mOnCancelListener = onCancelListener; @@ -315,6 +440,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Sets the callback that will be called if a key is dispatched to the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnKeyListener(OnKeyListener onKeyListener) { P.mOnKeyListener = onKeyListener; @@ -324,6 +451,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set a list of items to be displayed in the dialog as the content, you will be notified of the * selected item via the supplied listener. This should be an array type i.e. R.array.foo + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setItems(int itemsId, final OnClickListener listener) { P.mItems = P.mContext.getResources().getTextArray(itemsId); @@ -334,6 +463,8 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set a list of items to be displayed in the dialog as the content, you will be notified of the * selected item via the supplied listener. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setItems(CharSequence[] items, final OnClickListener listener) { P.mItems = items; @@ -348,6 +479,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * * @param adapter The {@link ListAdapter} to supply the list of items * @param listener The listener that will be called when an item is clicked. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener) { P.mAdapter = adapter; @@ -364,6 +497,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener The listener that will be called when an item is clicked. * @param labelColumn The column name on the cursor containing the string to display * in the label. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setCursor(final Cursor cursor, final OnClickListener listener, String labelColumn) { @@ -388,6 +523,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMultiChoiceItems(int itemsId, boolean[] checkedItems, final OnMultiChoiceClickListener listener) { @@ -412,6 +549,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, final OnMultiChoiceClickListener listener) { @@ -438,6 +577,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, final OnMultiChoiceClickListener listener) { @@ -461,6 +602,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(int itemsId, int checkedItem, final OnClickListener listener) { @@ -484,6 +627,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, final OnClickListener listener) { @@ -506,6 +651,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) { P.mItems = items; @@ -526,6 +673,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * @param listener notified when an item on the list is clicked. The dialog will not be * dismissed when an item is clicked. It will only be dismissed if clicked on a * button, if no buttons are supplied it's up to the user to dismiss the dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setSingleChoiceItems(ListAdapter adapter, int checkedItem, final OnClickListener listener) { P.mAdapter = adapter; @@ -540,6 +689,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * * @param listener The listener to be invoked. * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener) + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) { P.mOnItemSelectedListener = listener; @@ -549,9 +700,44 @@ public class AlertDialog extends Dialog implements DialogInterface { /** * Set a custom view to be the contents of the Dialog. If the supplied view is an instance * of a {@link ListView} the light background will be used. + * + * @param view The view to use as the contents of the Dialog. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setView(View view) { P.mView = view; + P.mViewSpacingSpecified = false; + return this; + } + + /** + * Set a custom view to be the contents of the Dialog, specifying the + * spacing to appear around that view. If the supplied view is an + * instance of a {@link ListView} the light background will be used. + * + * @param view The view to use as the contents of the Dialog. + * @param viewSpacingLeft Spacing between the left edge of the view and + * the dialog frame + * @param viewSpacingTop Spacing between the top edge of the view and + * the dialog frame + * @param viewSpacingRight Spacing between the right edge of the view + * and the dialog frame + * @param viewSpacingBottom Spacing between the bottom edge of the view + * and the dialog frame + * @return This Builder object to allow for chaining of calls to set + * methods + * + * @hide pending API review + */ + public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop, + int viewSpacingRight, int viewSpacingBottom) { + P.mView = view; + P.mViewSpacingSpecified = true; + P.mViewSpacingLeft = viewSpacingLeft; + P.mViewSpacingTop = viewSpacingTop; + P.mViewSpacingRight = viewSpacingRight; + P.mViewSpacingBottom = viewSpacingBottom; return this; } @@ -560,7 +746,8 @@ public class AlertDialog extends Dialog implements DialogInterface { * contents is. * * @param useInverseBackground Whether to use the inverse background - * @return This Builder object to allow for chaining of sets. + * + * @return This Builder object to allow for chaining of calls to set methods */ public Builder setInverseBackgroundForced(boolean useInverseBackground) { P.mForceInverseBackground = useInverseBackground; diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 342ffcf..0e41ae6 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -87,6 +87,7 @@ import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.WindowManagerImpl; +import android.view.inputmethod.InputMethodManager; import com.android.internal.policy.PolicyManager; @@ -104,6 +105,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.xmlpull.v1.XmlPullParserException; + class ReceiverRestrictedContext extends ContextWrapper { ReceiverRestrictedContext(Context base) { super(base); @@ -139,12 +142,12 @@ class ReceiverRestrictedContext extends ContextWrapper { * Common implementation of Context API, which Activity and other application * classes inherit. */ -@SuppressWarnings({"EmptyCatchBlock"}) class ApplicationContext extends Context { private final static String TAG = "ApplicationContext"; private final static boolean DEBUG_ICONS = false; private static final Object sSync = new Object(); + private static AlarmManager sAlarmManager; private static PowerManager sPowerManager; private static ConnectivityManager sConnectivityManager; private static WifiManager sWifiManager; @@ -288,12 +291,15 @@ class ApplicationContext extends Context { } throw new RuntimeException("Not supported in system context"); } + + private static File makeBackupFile(File prefsFile) { + return new File(prefsFile.getPath() + ".bak"); + } @Override public SharedPreferences getSharedPreferences(String name, int mode) { - File f; - f = makeFilename(getPreferencesDir(), name + ".xml"); SharedPreferencesImpl sp; + File f = makeFilename(getPreferencesDir(), name + ".xml"); synchronized (sSharedPrefs) { sp = sSharedPrefs.get(f); if (sp != null && !sp.hasFileChanged()) { @@ -301,15 +307,27 @@ class ApplicationContext extends Context { return sp; } } + + FileInputStream str = null; + File backup = makeBackupFile(f); + if (backup.exists()) { + f.delete(); + backup.renameTo(f); + } Map map = null; - try { - FileInputStream str = new FileInputStream(f); - map = XmlUtils.readMapXml(str); - str.close(); - } catch (org.xmlpull.v1.XmlPullParserException e) { - } catch (java.io.FileNotFoundException e) { - } catch (java.io.IOException e) { + if (f.exists()) { + try { + str = new FileInputStream(f); + map = XmlUtils.readMapXml(str); + str.close(); + } catch (org.xmlpull.v1.XmlPullParserException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (FileNotFoundException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (IOException e) { + Log.w(TAG, "getSharedPreferences", e); + } } synchronized (sSharedPrefs) { @@ -350,7 +368,7 @@ class ApplicationContext extends Context { File f = makeFilename(getFilesDir(), name); try { FileOutputStream fos = new FileOutputStream(f, append); - setFilePermissionsFromMode(f.toString(), mode, 0); + setFilePermissionsFromMode(f.getPath(), mode, 0); return fos; } catch (FileNotFoundException e) { } @@ -358,11 +376,11 @@ class ApplicationContext extends Context { File parent = f.getParentFile(); parent.mkdir(); FileUtils.setPermissions( - parent.toString(), + parent.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); FileOutputStream fos = new FileOutputStream(f, append); - setFilePermissionsFromMode(f.toString(), mode, 0); + setFilePermissionsFromMode(f.getPath(), mode, 0); return fos; } @@ -378,6 +396,16 @@ class ApplicationContext extends Context { if (mFilesDir == null) { mFilesDir = new File(getDataDirFile(), "files"); } + if (!mFilesDir.exists()) { + if(!mFilesDir.mkdirs()) { + Log.w(TAG, "Unable to create files directory"); + return null; + } + FileUtils.setPermissions( + mFilesDir.getPath(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, + -1, -1); + } return mFilesDir; } } @@ -394,7 +422,7 @@ class ApplicationContext extends Context { return null; } FileUtils.setPermissions( - mCacheDir.toString(), + mCacheDir.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } @@ -418,14 +446,14 @@ class ApplicationContext extends Context { public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) { File dir = getDatabasesDir(); if (!dir.isDirectory() && dir.mkdir()) { - FileUtils.setPermissions(dir.toString(), + FileUtils.setPermissions(dir.getPath(), FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1); } File f = makeFilename(dir, name); SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory); - setFilePermissionsFromMode(f.toString(), mode, 0); + setFilePermissionsFromMode(f.getPath(), mode, 0); return db; } @@ -844,7 +872,7 @@ class ApplicationContext extends Context { } else if (ACTIVITY_SERVICE.equals(name)) { return getActivityManager(); } else if (ALARM_SERVICE.equals(name)) { - return new AlarmManager(); + return getAlarmManager(); } else if (POWER_SERVICE.equals(name)) { return getPowerManager(); } else if (CONNECTIVITY_SERVICE.equals(name)) { @@ -878,6 +906,8 @@ class ApplicationContext extends Context { return getTelephonyManager(); } else if (CLIPBOARD_SERVICE.equals(name)) { return getClipboardManager(); + } else if (INPUT_METHOD_SERVICE.equals(name)) { + return InputMethodManager.getInstance(this); } return null; @@ -893,6 +923,17 @@ class ApplicationContext extends Context { return mActivityManager; } + private AlarmManager getAlarmManager() { + synchronized (sSync) { + if (sAlarmManager == null) { + IBinder b = ServiceManager.getService(ALARM_SERVICE); + IAlarmManager service = IAlarmManager.Stub.asInterface(b); + sAlarmManager = new AlarmManager(service); + } + } + return sAlarmManager; + } + private PowerManager getPowerManager() { synchronized (sSync) { if (sPowerManager == null) { @@ -1299,7 +1340,7 @@ class ApplicationContext extends Context { File file = makeFilename(getDataDirFile(), name); if (!file.exists()) { file.mkdir(); - setFilePermissionsFromMode(file.toString(), mode, + setFilePermissionsFromMode(file.getPath(), mode, FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH); } return file; @@ -1636,6 +1677,20 @@ class ApplicationContext extends Context { throw new RuntimeException("Package manager has died", e); } } + + @Override + public int getUidForSharedUser(String sharedUserName) + throws NameNotFoundException { + try { + int uid = mPM.getUidForSharedUser(sharedUserName); + if(uid != -1) { + return uid; + } + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + throw new NameNotFoundException("No shared userid for user:"+sharedUserName); + } @Override public List<PackageInfo> getInstalledPackages(int flags) { @@ -1899,7 +1954,9 @@ class ApplicationContext extends Context { if (app.packageName.equals("system")) { return mContext.mMainThread.getSystemContext().getResources(); } - Resources r = mContext.mMainThread.getTopLevelResources(app.publicSourceDir); + Resources r = mContext.mMainThread.getTopLevelResources( + app.uid == Process.myUid() ? app.sourceDir + : app.publicSourceDir); if (r != null) { return r; } @@ -2341,6 +2398,7 @@ class ApplicationContext extends Context { private static final class SharedPreferencesImpl implements SharedPreferences { private final File mFile; + private final File mBackupFile; private final int mMode; private Map mMap; private final FileStatus mFileStatus = new FileStatus(); @@ -2351,6 +2409,7 @@ class ApplicationContext extends Context { SharedPreferencesImpl( File file, int mode, Map initialContents) { mFile = file; + mBackupFile = makeBackupFile(file); mMode = mode; mMap = initialContents != null ? initialContents : new HashMap(); if (FileUtils.getFileStatus(file.getPath(), mFileStatus)) { @@ -2544,30 +2603,68 @@ class ApplicationContext extends Context { public Editor edit() { return new EditorImpl(); } + + private FileOutputStream createFileOutputStream(File file) { + FileOutputStream str = null; + try { + str = new FileOutputStream(file); + } catch (FileNotFoundException e) { + File parent = file.getParentFile(); + if (!parent.mkdir()) { + Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file); + return null; + } + FileUtils.setPermissions( + parent.getPath(), + FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, + -1, -1); + try { + str = new FileOutputStream(file); + } catch (FileNotFoundException e2) { + Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2); + } + } + return str; + } private boolean writeFileLocked() { + // Rename the current file so it may be used as a backup during the next read + if (mFile.exists()) { + if (!mFile.renameTo(mBackupFile)) { + Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile); + } + } + + // Attempt to write the file, delete the backup and return true as atomically as + // possible. If any exception occurs, delete the new file; next time we will restore + // from the backup. try { - FileOutputStream str; - try { - str = new FileOutputStream(mFile); - } catch (Exception e) { - File parent = mFile.getParentFile(); - parent.mkdir(); - FileUtils.setPermissions( - parent.toString(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, - -1, -1); - str = new FileOutputStream(mFile); + FileOutputStream str = createFileOutputStream(mFile); + if (str == null) { + return false; } XmlUtils.writeMapXml(mMap, str); str.close(); - setFilePermissionsFromMode(mFile.toString(), mMode, 0); + setFilePermissionsFromMode(mFile.getPath(), mMode, 0); if (FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) { mTimestamp = mFileStatus.mtime; } - } catch (org.xmlpull.v1.XmlPullParserException e) { - } catch (java.io.FileNotFoundException e) { - } catch (java.io.IOException e) { + + // Writing was successful, delete the backup file + if (!mBackupFile.delete()) { + Log.e(TAG, "Couldn't delete new backup file " + mBackupFile); + } + return true; + } catch (XmlPullParserException e) { + Log.w(TAG, "writeFileLocked: Got exception:", e); + } catch (IOException e) { + Log.w(TAG, "writeFileLocked: Got exception:", e); + } + // Clean up an unsuccessfully written file + if (mFile.exists()) { + if (!mFile.delete()) { + Log.e(TAG, "Couldn't clean up partially-written file " + mFile); + } } return false; } diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java index 7450559..ee5e0d5 100644 --- a/core/java/android/app/DatePickerDialog.java +++ b/core/java/android/app/DatePickerDialog.java @@ -20,8 +20,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; -import android.pim.DateFormat; import android.text.TextUtils.TruncateAt; +import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.widget.DatePicker; @@ -107,7 +107,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, DateFormatSymbols symbols = new DateFormatSymbols(); mWeekDays = symbols.getShortWeekdays(); - mDateFormat = DateFormat.getLongDateFormat(context); + mDateFormat = DateFormat.getMediumDateFormat(context); mCalendar = Calendar.getInstance(); updateTitle(mInitialYear, mInitialMonth, mInitialDay); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 2de21ed..353500e 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -213,6 +213,9 @@ public interface IActivityManager extends IInterface { * SIGUSR1 is delivered. All others are ignored. */ public void signalPersistentProcesses(int signal) throws RemoteException; + // Retrieve running application processes in the system + public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() + throws RemoteException; /** Information you can retrieve about a particular application. */ public static class ContentProviderHolder implements Parcelable { @@ -350,4 +353,5 @@ public interface IActivityManager extends IInterface { int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79; int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80; int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81; + int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82; } diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl index c7f20b9..cb42236 100755 --- a/core/java/android/app/IAlarmManager.aidl +++ b/core/java/android/app/IAlarmManager.aidl @@ -26,6 +26,7 @@ import android.app.PendingIntent; interface IAlarmManager { void set(int type, long triggerAtTime, in PendingIntent operation); void setRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation); + void setInexactRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation); void setTimeZone(String zone); void remove(in PendingIntent operation); } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index f80c947..17618ff 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -40,6 +40,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.Window; +import android.view.inputmethod.InputMethodManager; import java.io.File; import java.util.ArrayList; @@ -1262,7 +1263,7 @@ public class Instrumentation { * @param activity The activity being paused. */ public void callActivityOnPause(Activity activity) { - activity.onPause(); + activity.performPause(); } /* @@ -1392,8 +1393,8 @@ public class Instrumentation { * if there was no Activity found to run the given Intent. * * @param who The Context from which the activity is being started. - * @param whoThread The main thread of the Context from which the activity - * is being started. + * @param contextThread The main thread of the Context from which the activity + * is being started. * @param token Internal token identifying to the system who is starting * the activity; may be null. * @param target Which activity is perform the start (and thus receiving @@ -1416,8 +1417,9 @@ public class Instrumentation { * {@hide} */ public ActivityResult execStartActivity( - Context who, IApplicationThread whoThread, IBinder token, Activity target, + Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) { + IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 12e70e3..a24fcae 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -22,9 +22,6 @@ import android.os.Binder; import android.os.Bundle; import android.util.Config; import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; import android.view.Window; import java.util.ArrayList; @@ -114,13 +111,21 @@ public class LocalActivityManager { } if (r.curState == INITIALIZING) { + // Get the lastNonConfigurationInstance for the activity + HashMap<String,Object> lastNonConfigurationInstances = + mParent.getLastNonConfigurationChildInstances(); + Object instance = null; + if (lastNonConfigurationInstances != null) { + instance = lastNonConfigurationInstances.get(r.id); + } + // We need to have always created the activity. if (localLOGV) Log.v(TAG, r.id + ": starting " + r.intent); if (r.activityInfo == null) { r.activityInfo = mActivityThread.resolveActivityInfo(r.intent); } r.activity = mActivityThread.startActivityNow( - mParent, r.id, r.intent, r.activityInfo, r, r.instanceState); + mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance); if (r.activity == null) { return; } @@ -288,7 +293,6 @@ public class LocalActivityManager { // It's a brand new world. mActivities.put(id, r); mActivityArray.add(r); - } else if (r.activityInfo != null) { // If the new activity is the same as the current one, then // we may be able to reuse it. @@ -568,6 +572,32 @@ public class LocalActivityManager { moveToState(r, CREATED); } } + + /** + * Call onRetainNonConfigurationInstance on each child activity and store the + * results in a HashMap by id. Only construct the HashMap if there is a non-null + * object to store. Note that this does not support nested ActivityGroups. + * + * {@hide} + */ + public HashMap<String,Object> dispatchRetainNonConfigurationInstance() { + HashMap<String,Object> instanceMap = null; + + final int N = mActivityArray.size(); + for (int i=0; i<N; i++) { + LocalActivityRecord r = mActivityArray.get(i); + if ((r != null) && (r.activity != null)) { + Object instance = r.activity.onRetainNonConfigurationInstance(); + if (instance != null) { + if (instanceMap == null) { + instanceMap = new HashMap<String,Object>(); + } + instanceMap.put(r.id, instance); + } + } + } + return instanceMap; + } /** * Remove all activities from this LocalActivityManager, performing an diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index cc56385..ea67cdb 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -25,9 +25,9 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import android.pim.DateFormat; -import android.pim.DateUtils; import android.text.TextUtils; +import android.text.format.DateFormat; +import android.text.format.DateUtils; import android.widget.RemoteViews; /** diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index ba84903..b59e9dc 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -73,9 +73,22 @@ public final class PendingIntent implements Parcelable { * {@link #getService}: if the described PendingIntent already exists, * the current one is canceled before generating a new one. You can use * this to retrieve a new PendingIntent when you are only changing the - * extra data in the Intent. + * extra data in the Intent; by canceling the previous pending intent, + * this ensures that only entities given the new data will be able to + * launch it. If this assurance is not an issue, consider + * {@link #FLAG_UPDATE_CURRENT}. */ public static final int FLAG_CANCEL_CURRENT = 1<<28; + /** + * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}: if the described PendingIntent already exists, + * then keep it but its replace its extra data with what is in this new + * Intent. This can be used if you are creating intents where only the + * extras change, and don't care that any entities that received your + * previous PendingIntent will be able to launch it with your new + * extras even if they are not explicitly given to it. + */ + public static final int FLAG_UPDATE_CURRENT = 1<<27; /** * Exception thrown when trying to send through a PendingIntent that @@ -161,7 +174,8 @@ public final class PendingIntent implements Parcelable { * not used). * @param intent Intent of the activity to be launched. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, - * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by + * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, + * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. * @@ -195,7 +209,8 @@ public final class PendingIntent implements Parcelable { * not used). * @param intent The Intent to be broadcast. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, - * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by + * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, + * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. * @@ -230,7 +245,8 @@ public final class PendingIntent implements Parcelable { * not used). * @param intent An Intent describing the service to be started. * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE}, - * {@link #FLAG_CANCEL_CURRENT}, or any of the flags as supported by + * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT}, + * or any of the flags as supported by * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts * of the intent that can be supplied when the actual send happens. * diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java index 8b60cfa..c87e398 100644 --- a/core/java/android/app/ProgressDialog.java +++ b/core/java/android/app/ProgressDialog.java @@ -262,7 +262,7 @@ public class ProgressDialog extends AlertDialog { } public void setIndeterminate(boolean indeterminate) { - if (mHasStarted && (isIndeterminate() != indeterminate)) { + if (mProgress != null) { mProgress.setIndeterminate(indeterminate); } else { mIndeterminate = indeterminate; diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 5f3f9ef..2ce2db9 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -16,11 +16,14 @@ package android.app; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; @@ -48,10 +51,12 @@ import android.view.WindowManager; import android.view.View.OnFocusChangeListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.EditorInfo; import android.widget.AdapterView; -import android.widget.Button; import android.widget.CursorAdapter; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListAdapter; @@ -62,6 +67,7 @@ import android.widget.WrapperListAdapter; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicLong; @@ -100,7 +106,7 @@ public class SearchDialog extends Dialog { private TextView mBadgeLabel; private LinearLayout mSearchEditLayout; private EditText mSearchTextField; - private Button mGoButton; + private ImageButton mGoButton; private ListView mSuggestionsList; private ViewTreeObserver mViewTreeObserver = null; @@ -130,14 +136,14 @@ public class SearchDialog extends Dialog { private String mSuggestionAction = null; private Uri mSuggestionData = null; private String mSuggestionQuery = null; - + /** * Constructor - fires it up and makes it look like the search UI. * * @param context Application Context we can use for system acess */ public SearchDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Translucent); + super(context, com.android.internal.R.style.Theme_SearchBar); } /** @@ -149,21 +155,15 @@ public class SearchDialog extends Dialog { super.onCreate(savedInstanceState); Window theWindow = getWindow(); - theWindow.requestFeature(Window.FEATURE_NO_TITLE); - theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, - WindowManager.LayoutParams.FLAG_DIM_BEHIND); theWindow.setGravity(Gravity.TOP|Gravity.FILL_HORIZONTAL); setContentView(com.android.internal.R.layout.search_bar); - // Note: theWindow.setBackgroundDrawable(null) does not work here - you get blackness - theWindow.setBackgroundDrawableResource(android.R.color.transparent); - theWindow.setLayout(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); WindowManager.LayoutParams lp = theWindow.getAttributes(); - lp.dimAmount = 0.5f; lp.setTitle("Search Dialog"); + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE; theWindow.setAttributes(lp); // get the view elements for local access @@ -171,14 +171,14 @@ public class SearchDialog extends Dialog { mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge); mSearchEditLayout = (LinearLayout)findViewById(com.android.internal.R.id.search_edit_frame); mSearchTextField = (EditText) findViewById(com.android.internal.R.id.search_src_text); - mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn); + mGoButton = (ImageButton) findViewById(com.android.internal.R.id.search_go_btn); mSuggestionsList = (ListView) findViewById(com.android.internal.R.id.search_suggest_list); // attach listeners mSearchTextField.addTextChangedListener(mTextWatcher); mSearchTextField.setOnKeyListener(mTextKeyListener); mGoButton.setOnClickListener(mGoButtonClickListener); - mGoButton.setOnKeyListener(mGoButtonKeyListener); + mGoButton.setOnKeyListener(mButtonsKeyListener); mSuggestionsList.setOnItemClickListener(mSuggestionsListItemClickListener); mSuggestionsList.setOnKeyListener(mSuggestionsKeyListener); mSuggestionsList.setOnFocusChangeListener(mSuggestFocusListener); @@ -241,6 +241,7 @@ public class SearchDialog extends Dialog { if (mSuggestionsList != null) { mSuggestionsList.setVisibility(View.GONE); // prevent any flicker if was visible } + super.show(); setupSearchableInfo(); @@ -266,6 +267,17 @@ public class SearchDialog extends Dialog { initialQuery = ""; // This forces the preload to happen, triggering suggestions } mSearchTextField.setText(initialQuery); + + // If it is not for global search, that means the search dialog is + // launched to input a web address. + if (!globalSearch) { + mSearchTextField.setRawInputType(EditorInfo.TYPE_CLASS_TEXT + | EditorInfo.TYPE_TEXT_VARIATION_URI); + } else { + mSearchTextField.setRawInputType(EditorInfo.TYPE_CLASS_TEXT + | EditorInfo.TYPE_TEXT_VARIATION_NORMAL); + } + if (selectInitialQuery) { mSearchTextField.selectAll(); } else { @@ -424,7 +436,6 @@ public class SearchDialog extends Dialog { public void onConfigurationChanged(Configuration newConfig) { if (isShowing()) { // Redraw (resources may have changed) - updateSearchButton(); updateSearchBadge(); updateQueryHint(); } @@ -439,7 +450,6 @@ public class SearchDialog extends Dialog { mActivityContext = mSearchable.getActivityContext(getContext()); mProviderContext = mSearchable.getProviderContext(getContext(), mActivityContext); - updateSearchButton(); updateSearchBadge(); updateQueryHint(); } @@ -459,18 +469,6 @@ public class SearchDialog extends Dialog { } /** - * Update the text in the search button - */ - private void updateSearchButton() { - int textId = mSearchable.getSearchButtonText(); - if (textId == 0) { - textId = com.android.internal.R.string.search_go; - } - String goText = mActivityContext.getResources().getString(textId); - mGoButton.setText(goText); - } - - /** * Setup the search "Badge" if request by mode flags. */ private void updateSearchBadge() { @@ -1031,9 +1029,10 @@ public class SearchDialog extends Dialog { } /** - * React to typing in the GO button by refocusing to EditText. Continue typing the query. + * React to typing in the GO search button by refocusing to EditText. + * Continue typing the query. */ - View.OnKeyListener mGoButtonKeyListener = new View.OnKeyListener() { + View.OnKeyListener mButtonsKeyListener = new View.OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { // also guard against possible race conditions (late arrival after dismiss) if (mSearchable != null) { @@ -1054,7 +1053,7 @@ public class SearchDialog extends Dialog { } } }; - + /** * React to the user typing "enter" or other hardwired keys while typing in the search box. * This handles these special keys while the edit box has focus. diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 01babc4..5f25b90 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -48,6 +48,7 @@ import android.view.KeyEvent; * <li><a href="#ActionKeys">Action Keys</a> * <li><a href="#SearchabilityMetadata">Searchability Metadata</a> * <li><a href="#PassingSearchContext">Passing Search Context</a> + * <li><a href="#ProtectingUserPrivacy">Protecting User Privacy</a> * </ol> * * <a name="DeveloperGuide"></a> @@ -578,7 +579,7 @@ import android.view.KeyEvent; * file. Each element defines one of the keycodes you are interested in, * defines the conditions under which they are sent, and provides details * on how to communicate the action key event back to your searchable activity.</li> - * <li>In your intent receiver, if you wish, you can check for action keys by checking the + * <li>In your broadcast receiver, if you wish, you can check for action keys by checking the * extras field of the {@link android.content.Intent Intent}.</li> * </ul> * @@ -974,6 +975,36 @@ import android.view.KeyEvent; * appData.get...(); * appData.get...(); * }</pre> + * + * <a name="ProtectingUserPrivacy"></a> + * <h3>Protecting User Privacy</h3> + * + * <p>Many users consider their activities on the phone, including searches, to be private + * information. Applications that implement search should take steps to protect users' privacy + * wherever possible. This section covers two areas of concern, but you should consider your search + * design carefully and take any additional steps necessary. + * + * <p><b>Don't send personal information to servers, and if you do, don't log it.</b> + * "Personal information" is information that can personally identify your users, such as name, + * email address or billing information, or other data which can be reasonably linked to such + * information. If your application implements search with the assistance of a server, try to + * avoid sending personal information with your searches. For example, if you are searching for + * businesses near a zip code, you don't need to send the user ID as well - just send the zip code + * to the server. If you do need to send personal information, you should take steps to avoid + * logging it. If you must log it, you should protect that data very carefully, and erase it as + * soon as possible. + * + * <p><b>Provide the user with a way to clear their search history.</b> The Search Manager helps + * your application provide context-specific suggestions. Sometimes these suggestions are based + * on previous searches, or other actions taken by the user in an earlier session. A user may not + * wish for previous searches to be revealed to other users, for instance if they share their phone + * with a friend. If your application provides suggestions that can reveal previous activities, + * you should implement a "Clear History" menu, preference, or button. If you are using + * {@link android.provider.SearchRecentSuggestions}, you can simply call its + * {@link android.provider.SearchRecentSuggestions#clearHistory() clearHistory()} method from + * your "Clear History" UI. If you are implementing your own form of recent suggestions, you'll + * need to provide a similar a "clear history" API in your provider, and call it from your + * "Clear History" UI. */ public class SearchManager implements DialogInterface.OnDismissListener, DialogInterface.OnCancelListener @@ -1008,6 +1039,16 @@ public class SearchManager * activity that launched the search. */ public final static String APP_DATA = "app_data"; + + /** + * Intent app_data bundle key: Use this key with the bundle from + * {@link android.content.Intent#getBundleExtra + * content.Intent.getBundleExtra(APP_DATA)} to obtain the source identifier + * set by the activity that launched the search. + * + * @hide + */ + public final static String SOURCE = "source"; /** * Intent extra data key: Use this key with Intent.ACTION_SEARCH and diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 28b0615..6c08e75 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -163,7 +163,6 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac /** * Called by the system when the service is first created. Do not call this method directly. - * If you override this method, be sure to call super.onCreate(). */ public void onCreate() { } @@ -172,7 +171,6 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * Called by the system every time a client explicitly starts the service by calling * {@link android.content.Context#startService}, providing the arguments it supplied and a * unique integer token representing the start request. Do not call this method directly. - * If you override this method, be sure to call super.onStart(). * * @param intent The Intent supplied to {@link android.content.Context#startService}, * as given. @@ -189,7 +187,6 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac * service should clean up an resources it holds (threads, registered * receivers, etc) at this point. Upon return, there will be no more calls * in to this Service object and it is effectively dead. Do not call this method directly. - * If you override this method, be sure to call super.onDestroy(). */ public void onDestroy() { } @@ -375,4 +372,3 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac private Application mApplication = null; private IActivityManager mActivityManager = null; } - diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java index 107532e..002b01f 100644 --- a/core/java/android/app/TimePickerDialog.java +++ b/core/java/android/app/TimePickerDialog.java @@ -20,7 +20,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; -import android.pim.DateFormat; +import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.widget.TimePicker; |