summaryrefslogtreecommitdiffstats
path: root/core/java/android/app
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-03-18 11:33:14 -0700
committerJean-Baptiste Queru <jbq@google.com>2009-03-18 11:33:14 -0700
commit2a73de7b21a89aa2ba4c254d28658b49793425b2 (patch)
treeded5bcd581464b4174d81c373044b6d36eee58d2 /core/java/android/app
parent42e48026b21a962e5bf40344d738665ecbd9d74d (diff)
parentba87e3e6c985e7175152993b5efcc7dd2f0e1c93 (diff)
downloadframeworks_base-2a73de7b21a89aa2ba4c254d28658b49793425b2.zip
frameworks_base-2a73de7b21a89aa2ba4c254d28658b49793425b2.tar.gz
frameworks_base-2a73de7b21a89aa2ba4c254d28658b49793425b2.tar.bz2
Merge commit 'remotes/korg/cupcake' into merge
Conflicts: core/java/android/view/animation/TranslateAnimation.java core/jni/Android.mk core/res/res/values-en-rGB/strings.xml libs/audioflinger/AudioFlinger.cpp libs/surfaceflinger/LayerScreenshot.cpp packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
Diffstat (limited to 'core/java/android/app')
-rw-r--r--core/java/android/app/Activity.java105
-rw-r--r--core/java/android/app/ActivityManager.java93
-rw-r--r--core/java/android/app/ActivityManagerNative.java89
-rw-r--r--core/java/android/app/ActivityThread.java202
-rw-r--r--core/java/android/app/ApplicationContext.java60
-rw-r--r--core/java/android/app/ApplicationThreadNative.java18
-rw-r--r--core/java/android/app/Dialog.java4
-rw-r--r--core/java/android/app/ExpandableListActivity.java23
-rw-r--r--core/java/android/app/IActivityManager.java18
-rw-r--r--core/java/android/app/IApplicationThread.java2
-rw-r--r--core/java/android/app/Instrumentation.java2
-rw-r--r--core/java/android/app/IntentService.java74
-rw-r--r--core/java/android/app/LauncherActivity.java278
-rw-r--r--core/java/android/app/ListActivity.java26
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/NotificationManager.java4
-rw-r--r--core/java/android/app/PendingIntent.java13
-rw-r--r--core/java/android/app/SearchDialog.java193
-rw-r--r--core/java/android/app/SearchManager.java32
-rw-r--r--core/java/android/app/Service.java26
20 files changed, 1057 insertions, 214 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4dc4b6a..849a37d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -53,6 +53,7 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewManager;
import android.view.Window;
import android.view.WindowManager;
import android.view.ContextMenu.ContextMenuInfo;
@@ -93,11 +94,11 @@ import java.util.HashMap;
* {@link android.R.styleable#AndroidManifestActivity &lt;activity&gt;}
* declaration in their package's <code>AndroidManifest.xml</code>.</p>
*
- * <p>The Activity class is an important part of an
- * <a href="{@docRoot}intro/lifecycle.html">application's overall lifecycle</a>,
+ * <p>The Activity class is an important part of an application's overall lifecycle,
* and the way activities are launched and put together is a fundamental
- * part of the platform's
- * <a href="{@docRoot}intro/appmodel.html">application model</a>.</p>
+ * part of the platform's application model. For a detailed perspective on the structure of
+ * Android applications and lifecycles, please read the <em>Dev Guide</em> document on
+ * <a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>.</p>
*
* <p>Topics covered here:
* <ol>
@@ -527,7 +528,7 @@ import java.util.HashMap;
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start that activity.
*
- * <p>See the <a href="{@docRoot}devel/security.html">Security Model</a>
+ * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
* <a name="ProcessLifecycle"></a>
@@ -629,6 +630,9 @@ public class Activity extends ContextThemeWrapper
private WindowManager mWindowManager;
/*package*/ View mDecor = null;
+ /*package*/ boolean mWindowAdded = false;
+ /*package*/ boolean mVisibleFromServer = false;
+ /*package*/ boolean mVisibleFromClient = true;
private CharSequence mTitle;
private int mTitleColor = 0;
@@ -779,6 +783,8 @@ public class Activity extends ContextThemeWrapper
* @see #onPostCreate
*/
protected void onCreate(Bundle savedInstanceState) {
+ mVisibleFromClient = mWindow.getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowNoDisplay, true);
mCalled = true;
}
@@ -884,9 +890,9 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Called after {@link #onCreate} or {@link #onStop} when the current
- * activity is now being displayed to the user. It will
- * be followed by {@link #onRestart}.
+ * Called after {@link #onCreate} &mdash; or after {@link #onRestart} when
+ * the activity had been stopped, but is now again being displayed to the
+ * user. It will be followed by {@link #onResume}.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
@@ -901,9 +907,9 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Called after {@link #onStart} when the current activity is being
+ * Called after {@link #onStop} when the current activity is being
* re-displayed to the user (the user has navigated back to it). It will
- * be followed by {@link #onResume}.
+ * be followed by {@link #onStart} and then {@link #onResume}.
*
* <p>For activities that are using raw {@link Cursor} objects (instead of
* creating them through
@@ -917,6 +923,7 @@ public class Activity extends ContextThemeWrapper
* thrown.</em></p>
*
* @see #onStop
+ * @see #onStart
* @see #onResume
*/
protected void onRestart() {
@@ -1134,12 +1141,19 @@ public class Activity extends ContextThemeWrapper
/**
* Called as part of the activity lifecycle when an activity is about to go
* into the background as the result of user choice. For example, when the
- * user presses the Home key, {@link #onUserLeaving} will be called, but
+ * user presses the Home key, {@link #onUserLeaveHint} will be called, but
* when an incoming phone call causes the in-call Activity to be automatically
- * brought to the foreground, {@link #onUserLeaving} will not be called on
- * the activity being interrupted.
+ * brought to the foreground, {@link #onUserLeaveHint} will not be called on
+ * the activity being interrupted. In cases when it is invoked, this method
+ * is called right before the activity's {@link #onPause} callback.
+ *
+ * <p>This callback and {@link #onUserInteraction} are intended to help
+ * activities manage status bar notifications intelligently; specifically,
+ * for helping activities determine the proper time to cancel a notfication.
+ *
+ * @see #onUserInteraction()
*/
- protected void onUserLeaving() {
+ protected void onUserLeaveHint() {
}
/**
@@ -1207,7 +1221,7 @@ public class Activity extends ContextThemeWrapper
/**
* Called when you are no longer visible to the user. You will next
- * receive either {@link #onStart}, {@link #onDestroy}, or nothing,
+ * receive either {@link #onRestart}, {@link #onDestroy}, or nothing,
* depending on later user activity.
*
* <p>Note that this method may never be called, in low memory situations
@@ -1443,7 +1457,6 @@ public class Activity extends ContextThemeWrapper
* @return The Cursor that was returned by query().
*
* @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
- * @see #managedCommitUpdates
* @see #startManagingCursor
* @hide
*/
@@ -1475,7 +1488,6 @@ public class Activity extends ContextThemeWrapper
* @return The Cursor that was returned by query().
*
* @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
- * @see #managedCommitUpdates
* @see #startManagingCursor
*/
public final Cursor managedQuery(Uri uri,
@@ -1863,6 +1875,28 @@ public class Activity extends ContextThemeWrapper
return false;
}
+ /**
+ * Called whenever a key, touch, or trackball event is dispatched to the
+ * activity. Implement this method if you wish to know that the user has
+ * interacted with the device in some way while your activity is running.
+ * This callback and {@link #onUserLeaveHint} are intended to help
+ * activities manage status bar notifications intelligently; specifically,
+ * for helping activities determine the proper time to cancel a notfication.
+ *
+ * <p>All calls to your activity's {@link #onUserLeaveHint} callback will
+ * be accompanied by calls to {@link #onUserInteraction}. This
+ * ensures that your activity will be told of relevant user activity such
+ * as pulling down the notification pane and touching an item there.
+ *
+ * <p>Note that this callback will be invoked for the touch down action
+ * that begins a touch gesture, but may not be invoked for the touch-moved
+ * and touch-up actions that follow.
+ *
+ * @see #onUserLeaveHint()
+ */
+ public void onUserInteraction() {
+ }
+
public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
// Update window manager if: we have a view, that view is
// attached to its parent (which will be a RootView), and
@@ -1935,6 +1969,7 @@ public class Activity extends ContextThemeWrapper
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchKeyEvent(KeyEvent event) {
+ onUserInteraction();
if (getWindow().superDispatchKeyEvent(event)) {
return true;
}
@@ -1952,6 +1987,9 @@ public class Activity extends ContextThemeWrapper
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ onUserInteraction();
+ }
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
@@ -1969,6 +2007,7 @@ public class Activity extends ContextThemeWrapper
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTrackballEvent(MotionEvent ev) {
+ onUserInteraction();
if (getWindow().superDispatchTrackballEvent(ev)) {
return true;
}
@@ -2865,6 +2904,35 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Control whether this activity's main window is visible. This is intended
+ * only for the special case of an activity that is not going to show a
+ * UI itself, but can't just finish prior to onResume() because it needs
+ * to wait for a service binding or such. Setting this to false allows
+ * you to prevent your UI from being shown during that time.
+ *
+ * <p>The default value for this is taken from the
+ * {@link android.R.attr#windowNoDisplay} attribute of the activity's theme.
+ */
+ public void setVisible(boolean visible) {
+ if (mVisibleFromClient != visible) {
+ mVisibleFromClient = visible;
+ if (mVisibleFromServer) {
+ if (visible) makeVisible();
+ else mDecor.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ void makeVisible() {
+ if (!mWindowAdded) {
+ ViewManager wm = getWindowManager();
+ wm.addView(mDecor, getWindow().getAttributes());
+ mWindowAdded = true;
+ }
+ mDecor.setVisibility(View.VISIBLE);
+ }
+
+ /**
* Check to see whether this activity is in the process of finishing,
* either because you called {@link #finish} on it or someone else
* has requested that it finished. This is often used in
@@ -3482,7 +3550,8 @@ public class Activity extends ContextThemeWrapper
}
final void performUserLeaving() {
- onUserLeaving();
+ onUserInteraction();
+ onUserLeaveHint();
}
final void performStop() {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f9b9221..07520c9d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -19,16 +19,14 @@ package android.app;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.graphics.Bitmap;
import android.os.RemoteException;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.Parcelable.Creator;
import android.text.TextUtils;
-import android.util.Log;
import java.util.List;
/**
@@ -617,7 +615,59 @@ public class ActivityManager {
public String pkgList[];
+ /**
+ * Constant for {@link #importance}: this process is running the
+ * foreground UI.
+ */
+ public static final int IMPORTANCE_FOREGROUND = 100;
+
+ /**
+ * Constant for {@link #importance}: this process is running something
+ * that is considered to be actively visible to the user.
+ */
+ public static final int IMPORTANCE_VISIBLE = 200;
+
+ /**
+ * Constant for {@link #importance}: this process is contains services
+ * that should remain running.
+ */
+ public static final int IMPORTANCE_SERVICE = 300;
+
+ /**
+ * Constant for {@link #importance}: this process process contains
+ * background code that is expendable.
+ */
+ public static final int IMPORTANCE_BACKGROUND = 400;
+
+ /**
+ * Constant for {@link #importance}: this process is empty of any
+ * actively running code.
+ */
+ public static final int IMPORTANCE_EMPTY = 500;
+
+ /**
+ * The relative importance level that the system places on this
+ * process. May be one of {@link #IMPORTANCE_FOREGROUND},
+ * {@link #IMPORTANCE_VISIBLE}, {@link #IMPORTANCE_SERVICE},
+ * {@link #IMPORTANCE_BACKGROUND}, or {@link #IMPORTANCE_EMPTY}. These
+ * constants are numbered so that "more important" values are always
+ * smaller than "less important" values.
+ */
+ public int importance;
+
+ /**
+ * An additional ordering within a particular {@link #importance}
+ * category, providing finer-grained information about the relative
+ * utility of processes within a category. This number means nothing
+ * except that a smaller values are more recently used (and thus
+ * more important). Currently an LRU value is only maintained for
+ * the {@link #IMPORTANCE_BACKGROUND} category, though others may
+ * be maintained in the future.
+ */
+ public int lru;
+
public RunningAppProcessInfo() {
+ importance = IMPORTANCE_FOREGROUND;
}
public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
@@ -634,12 +684,16 @@ public class ActivityManager {
dest.writeString(processName);
dest.writeInt(pid);
dest.writeStringArray(pkgList);
+ dest.writeInt(importance);
+ dest.writeInt(lru);
}
public void readFromParcel(Parcel source) {
processName = source.readString();
pid = source.readInt();
pkgList = source.readStringArray();
+ importance = source.readInt();
+ lru = source.readInt();
}
public static final Creator<RunningAppProcessInfo> CREATOR =
@@ -671,4 +725,37 @@ public class ActivityManager {
return null;
}
}
+
+ /**
+ * Have the system perform a force stop of everything associated with
+ * the given application package. All processes that share its uid
+ * will be killed, all services it has running stopped, all activities
+ * removed, etc. In addition, a {@link Intent#ACTION_PACKAGE_RESTARTED}
+ * broadcast will be sent, so that any of its registered alarms can
+ * be stopped, notifications removed, etc.
+ *
+ * <p>You must hold the permission
+ * {@link android.Manifest.permission#RESTART_PACKAGES} to be able to
+ * call this method.
+ *
+ * @param packageName The name of the package to be stopped.
+ */
+ public void restartPackage(String packageName) {
+ try {
+ ActivityManagerNative.getDefault().restartPackage(packageName);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Get the device configuration attributes.
+ */
+ public ConfigurationInfo getDeviceConfigurationInfo() {
+ try {
+ return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ae9f3bf..53e6f34 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -83,6 +84,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
}
/**
+ * Convenience for checking whether the system is ready. For internal use only.
+ */
+ static public boolean isSystemReady() {
+ if (!sSystemReady) {
+ sSystemReady = getDefault().testIsSystemReady();
+ }
+ return sSystemReady;
+ }
+ static boolean sSystemReady = false;
+
+ /**
* Convenience for sending a sticky broadcast. For internal use only.
* If you don't care about permission, use null.
*/
@@ -959,6 +971,34 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_DEVICE_CONFIGURATION_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ ConfigurationInfo config = getDeviceConfigurationInfo();
+ reply.writeNoException();
+ config.writeToParcel(reply, 0);
+ return true;
+ }
+
+ case PROFILE_CONTROL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String process = data.readString();
+ boolean start = data.readInt() != 0;
+ String path = data.readString();
+ boolean res = profileControl(process, start, path);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
+ case PEEK_SERVICE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ Intent service = Intent.CREATOR.createFromParcel(data);
+ String resolvedType = data.readString();
+ IBinder binder = peekService(service, resolvedType);
+ reply.writeNoException();
+ reply.writeStrongBinder(binder);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1604,6 +1644,20 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+
+ public IBinder peekService(Intent service, String resolvedType) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ service.writeToParcel(data, 0);
+ data.writeString(resolvedType);
+ mRemote.transact(PEEK_SERVICE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ IBinder binder = reply.readStrongBinder();
+ reply.recycle();
+ data.recycle();
+ return binder;
+ }
public boolean startInstrumentation(ComponentName className, String profileFile,
int flags, Bundle arguments, IInstrumentationWatcher watcher)
@@ -2028,6 +2082,11 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+ public boolean testIsSystemReady()
+ {
+ /* this base class version is never called */
+ return true;
+ }
public int handleApplicationError(IBinder app, int flags,
String tag, String shortMsg, String longMsg,
byte[] crashData) throws RemoteException
@@ -2071,5 +2130,35 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_DEVICE_CONFIGURATION_TRANSACTION, data, reply, 0);
+ reply.readException();
+ ConfigurationInfo res = ConfigurationInfo.CREATOR.createFromParcel(reply);
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
+ public boolean profileControl(String process, boolean start,
+ String path) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(process);
+ data.writeInt(start ? 1 : 0);
+ data.writeString(path);
+ mRemote.transact(PROFILE_CONTROL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e4c1057..f49005e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -144,13 +144,19 @@ public final class ActivityThread {
return sPackageManager;
}
- DisplayMetrics getDisplayMetricsLocked() {
+ DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) {
+ if (mDisplayMetrics != null && !forceUpdate) {
+ return mDisplayMetrics;
+ }
if (mDisplay == null) {
WindowManager wm = WindowManagerImpl.getDefault();
mDisplay = wm.getDefaultDisplay();
}
- DisplayMetrics metrics = new DisplayMetrics();
+ DisplayMetrics metrics = mDisplayMetrics = new DisplayMetrics();
mDisplay.getMetrics(metrics);
+ //Log.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
+ // + metrics.heightPixels + " den=" + metrics.density
+ // + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
return metrics;
}
@@ -173,7 +179,7 @@ public final class ActivityThread {
if (assets.addAssetPath(appDir) == 0) {
return null;
}
- DisplayMetrics metrics = getDisplayMetricsLocked();
+ DisplayMetrics metrics = getDisplayMetricsLocked(false);
r = new Resources(assets, metrics, getConfiguration());
//Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration());
// XXX need to remove entries when weak references go away
@@ -235,7 +241,7 @@ public final class ActivityThread {
ApplicationContext.createSystemContext(mainThread);
mSystemContext.getResources().updateConfiguration(
mainThread.getConfiguration(),
- mainThread.getDisplayMetricsLocked());
+ mainThread.getDisplayMetricsLocked(false));
//Log.i(TAG, "Created system resources "
// + mSystemContext.getResources() + ": "
// + mSystemContext.getResources().getConfiguration());
@@ -1205,7 +1211,10 @@ public final class ActivityThread {
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%17s %8d";
private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
-
+
+ // Formatting for checkin service - update version if row format changes
+ private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
+
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
queueOrSendMessage(
@@ -1440,6 +1449,10 @@ public final class ActivityThread {
}
}
+ public void profilerControl(boolean start, String path) {
+ queueOrSendMessage(H.PROFILER_CONTROL, path, start ? 1 : 0);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
@@ -1462,7 +1475,101 @@ public final class ActivityThread {
long dalvikMax = runtime.totalMemory() / 1024;
long dalvikFree = runtime.freeMemory() / 1024;
long dalvikAllocated = dalvikMax - dalvikFree;
-
+ long viewInstanceCount = ViewDebug.getViewInstanceCount();
+ long viewRootInstanceCount = ViewDebug.getViewRootInstanceCount();
+ long appContextInstanceCount = ApplicationContext.getInstanceCount();
+ long activityInstanceCount = Activity.getInstanceCount();
+ int globalAssetCount = AssetManager.getGlobalAssetCount();
+ int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
+ int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
+ int binderProxyObjectCount = Debug.getBinderProxyObjectCount();
+ int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
+ int openSslSocketCount = OpenSSLSocketImpl.getInstanceCount();
+ long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
+ SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
+ SQLiteDebug.getPagerStats(stats);
+
+ // Check to see if we were called by checkin server. If so, print terse format.
+ boolean doCheckinFormat = false;
+ if (args != null) {
+ for (String arg : args) {
+ if ("-c".equals(arg)) doCheckinFormat = true;
+ }
+ }
+
+ // For checkin, we print one long comma-separated list of values
+ if (doCheckinFormat) {
+ // NOTE: if you change anything significant below, also consider changing
+ // ACTIVITY_THREAD_CHECKIN_VERSION.
+ String processName = (mBoundApplication != null)
+ ? mBoundApplication.processName : "unknown";
+
+ // Header
+ pw.print(ACTIVITY_THREAD_CHECKIN_VERSION); pw.print(',');
+ pw.print(Process.myPid()); pw.print(',');
+ pw.print(processName); pw.print(',');
+
+ // Heap info - max
+ pw.print(nativeMax); pw.print(',');
+ pw.print(dalvikMax); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeMax + dalvikMax); pw.print(',');
+
+ // Heap info - allocated
+ pw.print(nativeAllocated); pw.print(',');
+ pw.print(dalvikAllocated); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeAllocated + dalvikAllocated); pw.print(',');
+
+ // Heap info - free
+ pw.print(nativeFree); pw.print(',');
+ pw.print(dalvikFree); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeFree + dalvikFree); pw.print(',');
+
+ // Heap info - proportional set size
+ pw.print(memInfo.nativePss); pw.print(',');
+ pw.print(memInfo.dalvikPss); pw.print(',');
+ pw.print(memInfo.otherPss); pw.print(',');
+ pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
+
+ // Heap info - shared
+ pw.print(nativeShared); pw.print(',');
+ pw.print(dalvikShared); pw.print(',');
+ pw.print(otherShared); pw.print(',');
+ pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
+
+ // Heap info - private
+ pw.print(nativePrivate); pw.print(',');
+ pw.print(dalvikPrivate); pw.print(',');
+ pw.print(otherPrivate); pw.print(',');
+ pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
+
+ // Object counts
+ pw.print(viewInstanceCount); pw.print(',');
+ pw.print(viewRootInstanceCount); pw.print(',');
+ pw.print(appContextInstanceCount); pw.print(',');
+ pw.print(activityInstanceCount); pw.print(',');
+
+ pw.print(globalAssetCount); pw.print(',');
+ pw.print(globalAssetManagerCount); pw.print(',');
+ pw.print(binderLocalObjectCount); pw.print(',');
+ pw.print(binderProxyObjectCount); pw.print(',');
+
+ pw.print(binderDeathObjectCount); pw.print(',');
+ pw.print(openSslSocketCount); pw.print(',');
+
+ // SQL
+ pw.print(sqliteAllocated); pw.print(',');
+ pw.print(stats.databaseBytes / 1024); pw.print(',');
+ pw.print(stats.numPagers); pw.print(',');
+ pw.print((stats.totalBytes - stats.referencedBytes) / 1024); pw.print(',');
+ pw.print(stats.referencedBytes / 1024); pw.print('\n');
+
+ return;
+ }
+
+ // otherwise, show human-readable format
printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
@@ -1480,26 +1587,22 @@ public final class ActivityThread {
pw.println(" ");
pw.println(" Objects");
- printRow(pw, TWO_COUNT_COLUMNS, "Views:", ViewDebug.getViewInstanceCount(), "ViewRoots:",
- ViewDebug.getViewRootInstanceCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRoots:",
+ viewRootInstanceCount);
- printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", ApplicationContext.getInstanceCount(),
- "Activities:", Activity.getInstanceCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
+ "Activities:", activityInstanceCount);
- printRow(pw, TWO_COUNT_COLUMNS, "Assets:", AssetManager.getGlobalAssetCount(),
- "AssetManagers:", AssetManager.getGlobalAssetManagerCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "Assets:", globalAssetCount,
+ "AssetManagers:", globalAssetManagerCount);
- printRow(pw, TWO_COUNT_COLUMNS, "Local Binders:", Debug.getBinderLocalObjectCount(),
- "Proxy Binders:", Debug.getBinderProxyObjectCount());
- printRow(pw, ONE_COUNT_COLUMN, "Death Recipients:", Debug.getBinderDeathObjectCount());
-
- printRow(pw, ONE_COUNT_COLUMN, "OpenSSL Sockets:", OpenSSLSocketImpl.getInstanceCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "Local Binders:", binderLocalObjectCount,
+ "Proxy Binders:", binderProxyObjectCount);
+ printRow(pw, ONE_COUNT_COLUMN, "Death Recipients:", binderDeathObjectCount);
+ printRow(pw, ONE_COUNT_COLUMN, "OpenSSL Sockets:", openSslSocketCount);
+
// SQLite mem info
- long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
- SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
- SQLiteDebug.getPagerStats(stats);
-
pw.println(" ");
pw.println(" SQL");
printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "dbFiles:",
@@ -1542,6 +1645,7 @@ public final class ActivityThread {
public static final int LOW_MEMORY = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
+ public static final int PROFILER_CONTROL = 127;
String codeToString(int code) {
if (localLOGV) {
switch (code) {
@@ -1572,6 +1676,7 @@ public final class ActivityThread {
case LOW_MEMORY: return "LOW_MEMORY";
case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED";
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
+ case PROFILER_CONTROL: return "PROFILER_CONTROL";
}
}
return "(unknown)";
@@ -1671,6 +1776,9 @@ public final class ActivityThread {
case ACTIVITY_CONFIGURATION_CHANGED:
handleActivityConfigurationChanged((IBinder)msg.obj);
break;
+ case PROFILER_CONTROL:
+ handleProfilerControl(msg.arg1 != 0, (String)msg.obj);
+ break;
}
}
}
@@ -1751,6 +1859,7 @@ public final class ActivityThread {
final HashMap<String, WeakReference<PackageInfo>> mResourcePackages
= new HashMap<String, WeakReference<PackageInfo>>();
Display mDisplay = null;
+ DisplayMetrics mDisplayMetrics = null;
HashMap<String, WeakReference<Resources> > mActiveResources
= new HashMap<String, WeakReference<Resources> >();
@@ -1918,7 +2027,7 @@ public final class ActivityThread {
PackageInfo info = new PackageInfo(this, "android", context);
context.init(info, null, this);
context.getResources().updateConfiguration(
- getConfiguration(), getDisplayMetricsLocked());
+ getConfiguration(), getDisplayMetricsLocked(false));
mSystemContext = context;
//Log.i(TAG, "Created system resources " + context.getResources()
// + ": " + context.getResources().getConfiguration());
@@ -2557,7 +2666,10 @@ public final class ActivityThread {
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
- wm.addView(decor, l);
+ if (a.mVisibleFromClient) {
+ a.mWindowAdded = true;
+ wm.addView(decor, l);
+ }
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
@@ -2576,7 +2688,8 @@ public final class ActivityThread {
performConfigurationChanged(r.activity, r.newConfig);
r.newConfig = null;
}
- Log.v(TAG, "Resuming " + r + " with isForward=" + isForward);
+ if (localLOGV) Log.v(TAG, "Resuming " + r + " with isForward="
+ + isForward);
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
@@ -2588,8 +2701,11 @@ public final class ActivityThread {
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
- r.activity.mDecor.setVisibility(View.VISIBLE);
+ r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
+ if (r.activity.mVisibleFromClient) {
+ r.activity.makeVisible();
+ }
}
r.nextIdle = mNewActivities;
@@ -2800,18 +2916,22 @@ public final class ActivityThread {
View v = r.activity.mDecor;
if (v != null) {
if (show) {
- if (v.getVisibility() != View.VISIBLE) {
- v.setVisibility(View.VISIBLE);
+ if (!r.activity.mVisibleFromServer) {
+ r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
+ if (r.activity.mVisibleFromClient) {
+ r.activity.makeVisible();
+ }
}
if (r.newConfig != null) {
performConfigurationChanged(r.activity, r.newConfig);
r.newConfig = null;
}
} else {
- if (v.getVisibility() == View.VISIBLE) {
- v.setVisibility(View.INVISIBLE);
+ if (r.activity.mVisibleFromServer) {
+ r.activity.mVisibleFromServer = false;
mNumVisibleActivities--;
+ v.setVisibility(View.INVISIBLE);
}
}
}
@@ -3037,11 +3157,13 @@ public final class ActivityThread {
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;
if (v != null) {
- if (v.getVisibility() == View.VISIBLE) {
+ if (r.activity.mVisibleFromServer) {
mNumVisibleActivities--;
}
IBinder wtoken = v.getWindowToken();
- wm.removeViewImmediate(v);
+ if (r.activity.mWindowAdded) {
+ wm.removeViewImmediate(v);
+ }
if (wtoken != null) {
WindowManagerImpl.getDefault().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
@@ -3271,6 +3393,7 @@ public final class ActivityThread {
mConfiguration = new Configuration();
}
mConfiguration.updateFrom(config);
+ DisplayMetrics dm = getDisplayMetricsLocked(true);
// set it for java, this also affects newly created Resources
if (config.locale != null) {
@@ -3290,7 +3413,7 @@ public final class ActivityThread {
WeakReference<Resources> v = it.next();
Resources r = v.get();
if (r != null) {
- r.updateConfiguration(config, null);
+ r.updateConfiguration(config, dm);
//Log.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {
@@ -3318,6 +3441,21 @@ public final class ActivityThread {
performConfigurationChanged(r.activity, mConfiguration);
}
+ final void handleProfilerControl(boolean start, String path) {
+ if (start) {
+ File file = new File(path);
+ file.getParentFile().mkdirs();
+ try {
+ Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Profiling failed on path " + path
+ + " -- can the process access this path?");
+ }
+ } else {
+ Debug.stopMethodTracing();
+ }
+ }
+
final void handleLowMemory() {
ArrayList<ComponentCallbacks> callbacks
= new ArrayList<ComponentCallbacks>();
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 4236a00..3b5ad86 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -1487,7 +1487,7 @@ class ApplicationContext extends Context {
static final class ApplicationPackageManager extends PackageManager {
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
- throws NameNotFoundException {
+ throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfo(packageName, flags);
if (pi != null) {
@@ -1500,6 +1500,43 @@ class ApplicationContext extends Context {
throw new NameNotFoundException(packageName);
}
+ public Intent getLaunchIntentForPackage(String packageName)
+ throws NameNotFoundException {
+ // First see if the package has an INFO activity; the existence of
+ // such an activity is implied to be the desired front-door for the
+ // overall package (such as if it has multiple launcher entries).
+ Intent intent = getLaunchIntentForPackageCategory(this, packageName,
+ Intent.CATEGORY_INFO);
+ if (intent != null) {
+ return intent;
+ }
+
+ // Otherwise, try to find a main launcher activity.
+ return getLaunchIntentForPackageCategory(this, packageName,
+ Intent.CATEGORY_LAUNCHER);
+ }
+
+ // XXX This should be implemented as a call to the package manager,
+ // to reduce the work needed.
+ static Intent getLaunchIntentForPackageCategory(PackageManager pm,
+ String packageName, String category) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN, null);
+ intentToResolve.addCategory(category);
+ final List<ResolveInfo> apps =
+ pm.queryIntentActivities(intentToResolve, 0);
+ // I wish there were a way to directly get the "main" activity of a
+ // package but ...
+ for (ResolveInfo app : apps) {
+ if (app.activityInfo.packageName.equals(packageName)) {
+ intent.setClassName(packageName, app.activityInfo.name);
+ return intent;
+ }
+ }
+ return null;
+ }
+
@Override
public int[] getPackageGids(String packageName)
throws NameNotFoundException {
@@ -1630,6 +1667,15 @@ class ApplicationContext extends Context {
}
@Override
+ public String[] getSystemSharedLibraryNames() {
+ try {
+ return mPM.getSystemSharedLibraryNames();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
public int checkPermission(String permName, String pkgName) {
try {
return mPM.checkPermission(permName, pkgName);
@@ -1974,6 +2020,18 @@ class ApplicationContext extends Context {
getApplicationInfo(appPackageName, 0));
}
+ int mCachedSafeMode = -1;
+ @Override public boolean isSafeMode() {
+ try {
+ if (mCachedSafeMode < 0) {
+ mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
+ }
+ return mCachedSafeMode != 0;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
static void configurationChanged() {
synchronized (sSync) {
sIconCache.clear();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index d2cf55a..bcc9302 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -322,6 +322,15 @@ public abstract class ApplicationThreadNative extends Binder
requestPss();
return true;
}
+
+ case PROFILER_CONTROL_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ boolean start = data.readInt() != 0;
+ String path = data.readString();
+ profilerControl(start, path);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -654,5 +663,14 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
+ public void profilerControl(boolean start, String path) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeInt(start ? 1 : 0);
+ data.writeString(path);
+ mRemote.transact(PROFILER_CONTROL_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 951b48d..b09a57f 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -122,7 +122,7 @@ public class Dialog implements DialogInterface, Window.Callback,
* uses the window manager and theme from this context to
* present its UI.
* @param theme A style resource describing the theme to use for the
- * window. See <a href="{@docRoot}reference/available-resources.html#stylesandthemes">Style
+ * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
* and Theme Resources</a> for more information about defining and using
* styles. This theme is applied on top of the current theme in
* <var>context</var>. If 0, the default dialog theme will be used.
@@ -518,7 +518,7 @@ public class Dialog implements DialogInterface, Window.Callback,
private boolean isOutOfBounds(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
- final int slop = ViewConfiguration.getWindowTouchSlop();
+ final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
final View decorView = getWindow().getDecorView();
return (x < -slop) || (y < -slop)
|| (x > (decorView.getWidth()+slop))
diff --git a/core/java/android/app/ExpandableListActivity.java b/core/java/android/app/ExpandableListActivity.java
index 75dfcae..a2e048f 100644
--- a/core/java/android/app/ExpandableListActivity.java
+++ b/core/java/android/app/ExpandableListActivity.java
@@ -63,21 +63,21 @@ import java.util.Map;
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation=&quot;vertical&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
- * android:paddingLeft=&quot;8&quot;
- * android:paddingRight=&quot;8&quot;&gt;
+ * android:paddingLeft=&quot;8dp&quot;
+ * android:paddingRight=&quot;8dp&quot;&gt;
*
- * &lt;ExpandableListView id=&quot;android:list&quot;
+ * &lt;ExpandableListView android:id=&quot;@id/android:list&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#00FF00&quot;
* android:layout_weight=&quot;1&quot;
* android:drawSelectorOnTop=&quot;false&quot;/&gt;
*
- * &lt;TextView id=&quot;android:empty&quot;
+ * &lt;TextView android:id=&quot;@id/android:empty&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#FF0000&quot;
@@ -113,19 +113,19 @@ import java.util.Map;
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;
* android:orientation=&quot;vertical&quot;&gt;
*
- * &lt;TextView id=&quot;text1&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text1&quot;
+ * android:textSize=&quot;16sp&quot;
* android:textStyle=&quot;bold&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
*
- * &lt;TextView id=&quot;text2&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text2&quot;
+ * android:textSize=&quot;16sp&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
* &lt;/LinearLayout&gt;
@@ -162,7 +162,8 @@ public class ExpandableListActivity extends Activity implements
/**
* Override this to populate the context menu when an item is long pressed. menuInfo
- * will contain a {@link AdapterContextMenuInfo} whose position is a packed position
+ * will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo}
+ * whose packedPosition is a packed position
* that should be used with {@link ExpandableListView#getPackedPositionType(long)} and
* the other similar methods.
* <p>
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 353500e..2ac6160 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -22,6 +22,7 @@ import android.content.ContentProviderNative;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.ProviderInfo;
import android.content.res.Configuration;
@@ -127,7 +128,8 @@ public interface IActivityManager extends IInterface {
boolean doRebind) throws RemoteException;
/* oneway */
public void serviceDoneExecuting(IBinder token) throws RemoteException;
-
+ public IBinder peekService(Intent service, String resolvedType) throws RemoteException;
+
public boolean startInstrumentation(ComponentName className, String profileFile,
int flags, Bundle arguments, IInstrumentationWatcher watcher)
throws RemoteException;
@@ -216,6 +218,17 @@ public interface IActivityManager extends IInterface {
// Retrieve running application processes in the system
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
throws RemoteException;
+ // Get device configuration
+ public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException;
+
+ // Turn on/off profiling in a particular process.
+ public boolean profileControl(String process, boolean start,
+ String path) throws RemoteException;
+
+ /*
+ * Private non-Binder interfaces
+ */
+ /* package */ boolean testIsSystemReady();
/** Information you can retrieve about a particular application. */
public static class ContentProviderHolder implements Parcelable {
@@ -354,4 +367,7 @@ public interface IActivityManager extends IInterface {
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;
+ int GET_DEVICE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+83;
+ int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84;
+ int PROFILE_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+85;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 47476b5..9f3534b 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -86,6 +86,7 @@ public interface IApplicationThread extends IInterface {
void scheduleLowMemory() throws RemoteException;
void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
void requestPss() throws RemoteException;
+ void profilerControl(boolean start, String path) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -115,4 +116,5 @@ public interface IApplicationThread extends IInterface {
int SCHEDULE_ACTIVITY_CONFIGURATION_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+24;
int SCHEDULE_RELAUNCH_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+25;
int REQUEST_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26;
+ int PROFILER_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f96d787..f6a28b2 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1267,7 +1267,7 @@ public class Instrumentation {
}
/**
- * Perform calling of an activity's {@link Activity#onUserLeaving} method.
+ * Perform calling of an activity's {@link Activity#onUserLeaveHint} method.
* The default implementation simply calls through to that method.
*
* @param activity The activity being notified that the user has navigated away
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
new file mode 100644
index 0000000..2b12a2a
--- /dev/null
+++ b/core/java/android/app/IntentService.java
@@ -0,0 +1,74 @@
+package android.app;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * An abstract {@link Service} that serializes the handling of the Intents passed upon service
+ * start and handles them on a handler thread.
+ *
+ * <p>To use this class extend it and implement {@link #onHandleIntent}. The {@link Service} will
+ * automatically be stopped when the last enqueued {@link Intent} is handled.
+ */
+public abstract class IntentService extends Service {
+ private volatile Looper mServiceLooper;
+ private volatile ServiceHandler mServiceHandler;
+ private String mName;
+
+ private final class ServiceHandler extends Handler {
+ public ServiceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ onHandleIntent((Intent)msg.obj);
+ stopSelf(msg.arg1);
+ }
+ }
+
+ public IntentService(String name) {
+ super();
+ mName = name;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
+ thread.start();
+
+ mServiceLooper = thread.getLooper();
+ mServiceHandler = new ServiceHandler(mServiceLooper);
+ }
+
+ @Override
+ public void onStart(Intent intent, int startId) {
+ super.onStart(intent, startId);
+ Message msg = mServiceHandler.obtainMessage();
+ msg.arg1 = startId;
+ msg.obj = intent;
+ mServiceHandler.sendMessage(msg);
+ }
+
+ @Override
+ public void onDestroy() {
+ mServiceLooper.quit();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ /**
+ * Invoked on the Handler thread with the {@link Intent} that is passed to {@link #onStart}.
+ * Note that this will be invoked from a different thread than the one that handles the
+ * {@link #onStart} call.
+ */
+ protected abstract void onHandleIntent(Intent intent);
+}
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 8f0a4f5..d6fcbb1 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -18,14 +18,23 @@ package android.app;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
@@ -43,33 +52,59 @@ import java.util.List;
*
*/
public abstract class LauncherActivity extends ListActivity {
+
+ Intent mIntent;
+ PackageManager mPackageManager;
/**
+ * An item in the list
+ */
+ public static class ListItem {
+ public CharSequence label;
+ //public CharSequence description;
+ public Drawable icon;
+ public String packageName;
+ public String className;
+
+ ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
+ label = resolveInfo.loadLabel(pm);
+ if (label == null && resolveInfo.activityInfo != null) {
+ label = resolveInfo.activityInfo.name;
+ }
+
+ /*
+ if (resolveInfo.activityInfo != null &&
+ resolveInfo.activityInfo.applicationInfo != null) {
+ description = resolveInfo.activityInfo.applicationInfo.loadDescription(pm);
+ }
+ */
+
+ icon = resizer.createIconThumbnail(resolveInfo.loadIcon(pm));
+ packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+ className = resolveInfo.activityInfo.name;
+ }
+
+ public ListItem() {
+ }
+ }
+
+ /**
* Adapter which shows the set of activities that can be performed for a given intent.
*/
private class ActivityAdapter extends BaseAdapter implements Filterable {
private final Object lock = new Object();
- private ArrayList<ResolveInfo> mOriginalValues;
+ private ArrayList<ListItem> mOriginalValues;
- protected final Context mContext;
- protected final Intent mIntent;
protected final LayoutInflater mInflater;
- protected List<ResolveInfo> mActivitiesList;
+ protected List<ListItem> mActivitiesList;
private Filter mFilter;
-
- public ActivityAdapter(Context context, Intent intent) {
- mContext = context;
- mIntent = new Intent(intent);
- mIntent.setComponent(null);
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- PackageManager pm = context.getPackageManager();
- mActivitiesList = pm.queryIntentActivities(intent, 0);
- if (mActivitiesList != null) {
- Collections.sort(mActivitiesList, new ResolveInfo.DisplayNameComparator(pm));
- }
+
+ public ActivityAdapter() {
+ mInflater = (LayoutInflater) LauncherActivity.this.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mActivitiesList = makeListItems();
}
public Intent intentForPosition(int position) {
@@ -78,8 +113,8 @@ public abstract class LauncherActivity extends ListActivity {
}
Intent intent = new Intent(mIntent);
- ActivityInfo ai = mActivitiesList.get(position).activityInfo;
- intent.setClassName(ai.applicationInfo.packageName, ai.name);
+ ListItem item = mActivitiesList.get(position);
+ intent.setClassName(item.packageName, item.className);
return intent;
}
@@ -99,7 +134,7 @@ public abstract class LauncherActivity extends ListActivity {
View view;
if (convertView == null) {
view = mInflater.inflate(
- com.android.internal.R.layout.simple_list_item_1, parent, false);
+ com.android.internal.R.layout.activity_list_item_2, parent, false);
} else {
view = convertView;
}
@@ -107,35 +142,22 @@ public abstract class LauncherActivity extends ListActivity {
return view;
}
- private char getCandidateLetter(ResolveInfo info) {
- PackageManager pm = mContext.getPackageManager();
- CharSequence label = info.loadLabel(pm);
-
- if (label == null) {
- label = info.activityInfo.name;
- }
-
- return Character.toLowerCase(label.charAt(0));
+ private void bindView(View view, ListItem item) {
+ TextView text = (TextView) view;
+ text.setText(item.label);
+ text.setCompoundDrawablesWithIntrinsicBounds(item.icon, null, null, null);
}
-
- private void bindView(View view, ResolveInfo info) {
- TextView text = (TextView) view.findViewById(com.android.internal.R.id.text1);
-
- PackageManager pm = mContext.getPackageManager();
- CharSequence label = info.loadLabel(pm);
- text.setText(label != null ? label : info.activityInfo.name);
- }
-
+
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
-
+
/**
- * <p>An array filters constrains the content of the array adapter with a prefix. Each item that
- * does not start with the supplied prefix is removed from the list.</p>
+ * An array filters constrains the content of the array adapter with a prefix. Each
+ * item that does not start with the supplied prefix is removed from the list.
*/
private class ArrayFilter extends Filter {
@Override
@@ -144,39 +166,35 @@ public abstract class LauncherActivity extends ListActivity {
if (mOriginalValues == null) {
synchronized (lock) {
- mOriginalValues = new ArrayList<ResolveInfo>(mActivitiesList);
+ mOriginalValues = new ArrayList<ListItem>(mActivitiesList);
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (lock) {
- ArrayList<ResolveInfo> list = new ArrayList<ResolveInfo>(mOriginalValues);
+ ArrayList<ListItem> list = new ArrayList<ListItem>(mOriginalValues);
results.values = list;
results.count = list.size();
}
} else {
- final PackageManager pm = mContext.getPackageManager();
final String prefixString = prefix.toString().toLowerCase();
- ArrayList<ResolveInfo> values = mOriginalValues;
+ ArrayList<ListItem> values = mOriginalValues;
int count = values.size();
- ArrayList<ResolveInfo> newValues = new ArrayList<ResolveInfo>(count);
+ ArrayList<ListItem> newValues = new ArrayList<ListItem>(count);
for (int i = 0; i < count; i++) {
- ResolveInfo value = values.get(i);
+ ListItem item = values.get(i);
- final CharSequence label = value.loadLabel(pm);
- final CharSequence name = label != null ? label : value.activityInfo.name;
-
- String[] words = name.toString().toLowerCase().split(" ");
+ String[] words = item.label.toString().toLowerCase().split(" ");
int wordCount = words.length;
for (int k = 0; k < wordCount; k++) {
final String word = words[k];
if (word.startsWith(prefixString)) {
- newValues.add(value);
+ newValues.add(item);
break;
}
}
@@ -192,7 +210,7 @@ public abstract class LauncherActivity extends ListActivity {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
//noinspection unchecked
- mActivitiesList = (List<ResolveInfo>) results.values;
+ mActivitiesList = (List<ListItem>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
@@ -201,19 +219,119 @@ public abstract class LauncherActivity extends ListActivity {
}
}
}
-
-
+
+ /**
+ * Utility class to resize icons to match default icon size.
+ */
+ public class IconResizer {
+ // Code is borrowed from com.android.launcher.Utilities.
+ private int mIconWidth = -1;
+ private int mIconHeight = -1;
+
+ private final Rect mOldBounds = new Rect();
+ private Canvas mCanvas = new Canvas();
+
+ public IconResizer() {
+ mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+
+ final Resources resources = LauncherActivity.this.getResources();
+ mIconWidth = mIconHeight = (int) resources.getDimension(
+ android.R.dimen.app_icon_size);
+ }
+
+ /**
+ * Returns a Drawable representing the thumbnail of the specified Drawable.
+ * The size of the thumbnail is defined by the dimension
+ * android.R.dimen.launcher_application_icon_size.
+ *
+ * This method is not thread-safe and should be invoked on the UI thread only.
+ *
+ * @param icon The icon to get a thumbnail of.
+ *
+ * @return A thumbnail for the specified icon or the icon itself if the
+ * thumbnail could not be created.
+ */
+ public Drawable createIconThumbnail(Drawable icon) {
+ int width = mIconWidth;
+ int height = mIconHeight;
+
+ final int iconWidth = icon.getIntrinsicWidth();
+ final int iconHeight = icon.getIntrinsicHeight();
+
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(width);
+ painter.setIntrinsicHeight(height);
+ }
+
+ if (width > 0 && height > 0) {
+ if (width < iconWidth || height < iconHeight) {
+ final float ratio = (float) iconWidth / iconHeight;
+
+ if (iconWidth > iconHeight) {
+ height = (int) (width / ratio);
+ } else if (iconHeight > iconWidth) {
+ width = (int) (height * ratio);
+ }
+
+ final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
+ Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ // Copy the old bounds to restore them later
+ // If we were to do oldBounds = icon.getBounds(),
+ // the call to setBounds() that follows would
+ // change the same instance and we would lose the
+ // old bounds
+ mOldBounds.set(icon.getBounds());
+ final int x = (mIconWidth - width) / 2;
+ final int y = (mIconHeight - height) / 2;
+ icon.setBounds(x, y, x + width, y + height);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ icon = new BitmapDrawable(thumb);
+ } else if (iconWidth < width && iconHeight < height) {
+ final Bitmap.Config c = Bitmap.Config.ARGB_8888;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ mOldBounds.set(icon.getBounds());
+ final int x = (width - iconWidth) / 2;
+ final int y = (height - iconHeight) / 2;
+ icon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ icon = new BitmapDrawable(thumb);
+ }
+ }
+
+ return icon;
+ }
+ }
+
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mPackageManager = getPackageManager();
+
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setProgressBarIndeterminateVisibility(true);
+ setContentView(com.android.internal.R.layout.activity_list);
- mAdapter = new ActivityAdapter(this, getTargetIntent());
+
+ mIntent = new Intent(getTargetIntent());
+ mIntent.setComponent(null);
+ mAdapter = new ActivityAdapter();
setListAdapter(mAdapter);
getListView().setTextFilterEnabled(true);
+
+ setProgressBarIndeterminateVisibility(false);
}
-
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = ((ActivityAdapter)mAdapter).intentForPosition(position);
@@ -221,6 +339,42 @@ public abstract class LauncherActivity extends ListActivity {
startActivity(intent);
}
- protected abstract Intent getTargetIntent();
-
+ /**
+ * Return the actual Intent for a specific position in our
+ * {@link android.widget.ListView}.
+ * @param position The item whose Intent to return
+ */
+ protected Intent intentForPosition(int position) {
+ ActivityAdapter adapter = (ActivityAdapter) mAdapter;
+ return adapter.intentForPosition(position);
+ }
+
+ /**
+ * Get the base intent to use when running
+ * {@link PackageManager#queryIntentActivities(Intent, int)}.
+ */
+ protected Intent getTargetIntent() {
+ return new Intent();
+ }
+
+ /**
+ * Perform the query to determine which results to show and return a list of them.
+ */
+ public List<ListItem> makeListItems() {
+ // Load all matching activities and sort correctly
+ List<ResolveInfo> list = mPackageManager.queryIntentActivities(mIntent,
+ /* no flags */ 0);
+ Collections.sort(list, new ResolveInfo.DisplayNameComparator(mPackageManager));
+
+ IconResizer resizer = new IconResizer();
+
+ ArrayList<ListItem> result = new ArrayList<ListItem>(list.size());
+ int listSize = list.size();
+ for (int i = 0; i < listSize; i++) {
+ ResolveInfo resolveInfo = list.get(i);
+ result.add(new ListItem(mPackageManager, resolveInfo, resizer));
+ }
+
+ return result;
+ }
}
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 2818937..5523c18 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -53,22 +53,22 @@ import android.widget.ListView;
* </p>
*
* <pre>
- * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation=&quot;vertical&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
- * android:paddingLeft=&quot;8&quot;
- * android:paddingRight=&quot;8&quot;&gt;
+ * android:paddingLeft=&quot;8dp&quot;
+ * android:paddingRight=&quot;8dp&quot;&gt;
*
- * &lt;ListView id=&quot;android:list&quot;
+ * &lt;ListView android:id=&quot;@id/android:list&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#00FF00&quot;
* android:layout_weight=&quot;1&quot;
* android:drawSelectorOnTop=&quot;false&quot;/&gt;
*
- * &lt;TextView id=&quot;android:empty&quot;
+ * &lt;TextView id=&quot;@id/android:empty&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#FF0000&quot;
@@ -99,19 +99,19 @@ import android.widget.ListView;
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;
* android:orientation=&quot;vertical&quot;&gt;
*
- * &lt;TextView id=&quot;text1&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text1&quot;
+ * android:textSize=&quot;16sp&quot;
* android:textStyle=&quot;bold&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
*
- * &lt;TextView id=&quot;text2&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text2&quot;
+ * android:textSize=&quot;16sp&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
* &lt;/LinearLayout&gt;
@@ -142,8 +142,8 @@ import android.widget.ListView;
* public class MyListAdapter extends ListActivity {
*
* &#064;Override
- * protected void onCreate(Bundle icicle){
- * super.onCreate(icicle);
+ * protected void onCreate(Bundle savedInstanceState){
+ * super.onCreate(savedInstanceState);
*
* // We'll define a custom screen layout here (the one shown above), but
* // typically, you could just use the standard ListActivity layout.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ea67cdb..51fddb1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -90,8 +90,9 @@ public class Notification implements Parcelable
* The intent to execute when the expanded status entry is clicked. If
* this is an activity, it must include the
* {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
- * that you take care of task management as described in the
- * <a href="{@docRoot}intro/appmodel.html">application model</a> document.
+ * that you take care of task management as described in the <em>Activities and Tasks</em>
+ * section of the <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application
+ * Fundamentals</a> document.
*/
public PendingIntent contentIntent;
@@ -420,8 +421,8 @@ public class Notification implements Parcelable
* @param contentIntent The intent to launch when the user clicks the expanded notification.
* If this is an activity, it must include the
* {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
- * that you take care of task management as described in the
- * <a href="{@docRoot}intro/appmodel.html">application model</a> document.
+ * that you take care of task management as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>.
*/
public void setLatestEventInfo(Context context,
CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index afb3827..39edab7 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -82,9 +82,7 @@ public class NotificationManager
* @param id An identifier for this notification unique within your
* application.
* @param notification A {@link Notification} object describing how to
- * notify the user, other than the view you're providing. If you
- * pass null, there will be no persistent notification and no
- * flashing, vibration, etc.
+ * notify the user, other than the view you're providing. Must not be null.
*/
public void notify(int id, Notification notification)
{
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index b59e9dc..1bed706 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -426,13 +426,9 @@ public final class PendingIntent implements Parcelable {
*/
@Override
public boolean equals(Object otherObj) {
- if (otherObj == null) {
- return false;
- }
- try {
+ if (otherObj instanceof PendingIntent) {
return mTarget.asBinder().equals(((PendingIntent)otherObj)
.mTarget.asBinder());
- } catch (ClassCastException e) {
}
return false;
}
@@ -442,6 +438,13 @@ public final class PendingIntent implements Parcelable {
return mTarget.asBinder().hashCode();
}
+ @Override
+ public String toString() {
+ return "PendingIntent{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " target " + (mTarget != null ? mTarget.asBinder() : null) + "}";
+ }
+
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 2e2a1a1..64288d2 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;
@@ -29,11 +32,11 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.server.search.SearchableInfo;
+import android.speech.RecognizerIntent;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
@@ -50,6 +53,7 @@ import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CursorAdapter;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
@@ -94,6 +98,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
private TextView mBadgeLabel;
private AutoCompleteTextView mSearchTextField;
private Button mGoButton;
+ private ImageButton mVoiceButton;
// interaction with searchable application
private ComponentName mLaunchComponent;
@@ -115,10 +120,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
private Uri mSuggestionData = null;
private String mSuggestionQuery = null;
+ // For voice searching
+ private Intent mVoiceWebSearchIntent;
+ private Intent mVoiceAppSearchIntent;
+
// support for AutoCompleteTextView suggestions display
private SuggestionsAdapter mSuggestionsAdapter;
-
/**
* Constructor - fires it up and makes it look like the search UI.
*
@@ -153,12 +161,15 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mSearchTextField = (AutoCompleteTextView)
findViewById(com.android.internal.R.id.search_src_text);
mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn);
+ mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn);
// attach listeners
mSearchTextField.addTextChangedListener(mTextWatcher);
mSearchTextField.setOnKeyListener(mTextKeyListener);
mGoButton.setOnClickListener(mGoButtonClickListener);
mGoButton.setOnKeyListener(mButtonsKeyListener);
+ mVoiceButton.setOnClickListener(mVoiceButtonClickListener);
+ mVoiceButton.setOnKeyListener(mButtonsKeyListener);
// pre-hide all the extraneous elements
mBadgeLabel.setVisibility(View.GONE);
@@ -169,13 +180,19 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
setCanceledOnTouchOutside(true);
// Set up broadcast filters
- mCloseDialogsFilter = new
- IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ mCloseDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mPackageFilter = new IntentFilter();
mPackageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
mPackageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
mPackageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
mPackageFilter.addDataScheme("package");
+
+ // Save voice intent for later queries/launching
+ mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+ mVoiceWebSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
+ RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
+
+ mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
}
/**
@@ -236,7 +253,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mSearchTextField.setAdapter(mSuggestionsAdapter);
mSearchTextField.setText(initialQuery);
} else {
- mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable);
+ mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable,
+ mSearchTextField);
mSearchTextField.setAdapter(mSuggestionsAdapter);
// finally, load the user's initial text (which may trigger suggestions)
@@ -261,16 +279,15 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
- * Dismiss the search dialog.
+ * The search dialog is being dismissed, so handle all of the local shutdown operations.
*
- * This function is designed to be idempotent so it can be safely called at any time
+ * This function is designed to be idempotent so that dismiss() can be safely called at any time
* (even if already closed) and more likely to really dump any memory. No leaks!
*/
@Override
- public void dismiss() {
- if (isShowing()) {
- super.dismiss();
- }
+ public void onStop() {
+ super.onStop();
+
setOnCancelListener(null);
setOnDismissListener(null);
@@ -281,6 +298,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// This is OK - it just means we didn't have any registered
}
+ // close any leftover cursor
+ if (mSuggestionsAdapter != null) {
+ mSuggestionsAdapter.changeCursor(null);
+ }
+
// dump extra memory we're hanging on to
mLaunchComponent = null;
mAppSearchData = null;
@@ -408,6 +430,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
updateSearchButton();
updateSearchBadge();
updateQueryHint();
+ updateVoiceButton();
// In order to properly configure the input method (if one is being used), we
// need to let it know if we'll be providing suggestions. Although it would be
@@ -426,6 +449,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
}
mSearchTextField.setInputType(inputType);
+ mSearchTextField.setImeOptions(mSearchable.getImeOptions());
}
}
@@ -500,6 +524,30 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
+ * Update the visibility of the voice button. There are actually two voice search modes,
+ * either of which will activate the button.
+ */
+ private void updateVoiceButton() {
+ int visibility = View.GONE;
+ if (mSearchable.getVoiceSearchEnabled()) {
+ Intent testIntent = null;
+ if (mSearchable.getVoiceSearchLaunchWebSearch()) {
+ testIntent = mVoiceWebSearchIntent;
+ } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
+ testIntent = mVoiceAppSearchIntent;
+ }
+ if (testIntent != null) {
+ ResolveInfo ri = getContext().getPackageManager().
+ resolveActivity(testIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (ri != null) {
+ visibility = View.VISIBLE;
+ }
+ }
+ }
+ mVoiceButton.setVisibility(visibility);
+ }
+
+ /**
* Listeners of various types
*/
@@ -642,11 +690,97 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
};
/**
+ * React to a click in the voice search button.
+ */
+ View.OnClickListener mVoiceButtonClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ if (mSearchable.getVoiceSearchLaunchWebSearch()) {
+ getContext().startActivity(mVoiceWebSearchIntent);
+ dismiss();
+ } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
+ Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);
+ getContext().startActivity(appSearchIntent);
+ dismiss();
+ }
+ } catch (ActivityNotFoundException e) {
+ // Should not happen, since we check the availability of
+ // voice search before showing the button. But just in case...
+ Log.w(LOG_TAG, "Could not find voice search activity");
+ }
+ }
+ };
+
+ /**
+ * Create and return an Intent that can launch the voice search activity, perform a specific
+ * voice transcription, and forward the results to the searchable activity.
+ *
+ * @param baseIntent The voice app search intent to start from
+ * @return A completely-configured intent ready to send to the voice search activity
+ */
+ private Intent createVoiceAppSearchIntent(Intent baseIntent) {
+ // create the necessary intent to set up a search-and-forward operation
+ // in the voice search system. We have to keep the bundle separate,
+ // because it becomes immutable once it enters the PendingIntent
+ Intent queryIntent = new Intent(Intent.ACTION_SEARCH);
+ queryIntent.setComponent(mSearchable.mSearchActivity);
+ PendingIntent pending = PendingIntent.getActivity(
+ getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT);
+
+ // Now set up the bundle that will be inserted into the pending intent
+ // when it's time to do the search. We always build it here (even if empty)
+ // because the voice search activity will always need to insert "QUERY" into
+ // it anyway.
+ Bundle queryExtras = new Bundle();
+ if (mAppSearchData != null) {
+ queryExtras.putBundle(SearchManager.APP_DATA, mAppSearchData);
+ }
+
+ // Now build the intent to launch the voice search. Add all necessary
+ // extras to launch the voice recognizer, and then all the necessary extras
+ // to forward the results to the searchable activity
+ Intent voiceIntent = new Intent(baseIntent);
+
+ // Add all of the configuration options supplied by the searchable's metadata
+ String languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM;
+ String prompt = null;
+ String language = null;
+ int maxResults = 1;
+ Resources resources = mActivityContext.getResources();
+ if (mSearchable.getVoiceLanguageModeId() != 0) {
+ languageModel = resources.getString(mSearchable.getVoiceLanguageModeId());
+ }
+ if (mSearchable.getVoicePromptTextId() != 0) {
+ prompt = resources.getString(mSearchable.getVoicePromptTextId());
+ }
+ if (mSearchable.getVoiceLanguageId() != 0) {
+ language = resources.getString(mSearchable.getVoiceLanguageId());
+ }
+ if (mSearchable.getVoiceMaxResults() != 0) {
+ maxResults = mSearchable.getVoiceMaxResults();
+ }
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults);
+
+ // Add the values that configure forwarding the results
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras);
+
+ return voiceIntent;
+ }
+
+ /**
* 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.
*/
View.OnKeyListener mTextKeyListener = new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ cancel();
+ return true;
+ }
// also guard against possible race conditions (late arrival after dismiss)
if (mSearchable != null &&
TextUtils.getTrimmedLength(mSearchTextField.getText()) > 0) {
@@ -661,7 +795,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// otherwise, dispatch an "edit view" key
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
if (event.getAction() == KeyEvent.ACTION_UP) {
v.cancelLongPress();
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
@@ -700,9 +833,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// also guard against possible race conditions (late arrival after dismiss)
if (mSearchable != null) {
handled = doSuggestionsKey(v, keyCode, event);
- if (!handled) {
- handled = refocusingKeyListener(v, keyCode, event);
- }
}
return handled;
}
@@ -793,24 +923,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
};
/**
- * UI-thread handling of dialog dismiss. Called by mBroadcastReceiver.onReceive().
- *
- * TODO: This is a really heavyweight solution for something that should be so simple.
- * For example, we already have a handler, in our superclass, why aren't we sharing that?
- * I think we need to investigate simplifying this entire methodology, or perhaps boosting
- * it up into the Dialog class.
- */
- private static final int MESSAGE_DISMISS = 0;
- private Handler mDismissHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MESSAGE_DISMISS) {
- dismiss();
- }
- }
- };
-
- /**
* Various ways to launch searches
*/
@@ -907,6 +1019,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
* @param jamQuery True means to set the query, false means to reset it to the user's choice
*/
private void jamSuggestionQuery(boolean jamQuery, AdapterView<?> parent, int position) {
+ // quick check against race conditions
+ if (mSearchable == null) {
+ return;
+ }
+
mSuggestionsAdapter.setNonUserQuery(true); // disables any suggestions processing
if (jamQuery) {
CursorAdapter ca = getSuggestionsAdapter(parent);
@@ -1180,10 +1297,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// These private variables are shared by the filter thread and must be protected
private WeakReference<Cursor> mRecentCursor = new WeakReference<Cursor>(null);
private boolean mNonUserQuery = false;
+ private AutoCompleteTextView mParentView;
- public SuggestionsAdapter(Context context, SearchableInfo searchable) {
+ public SuggestionsAdapter(Context context, SearchableInfo searchable,
+ AutoCompleteTextView actv) {
super(context, -1, null, null, null);
mSearchable = searchable;
+ mParentView = actv;
// set up provider resources (gives us icons, etc.)
Context activityContext = mSearchable.getActivityContext(mContext);
@@ -1296,9 +1416,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
to = ONE_LINE_TO;
}
}
+ // Force the underlying ListView to discard and reload all layouts
+ // (Note, this should be optimized for cases where layout/cursor remain same)
+ mParentView.resetListAndClearViews();
// Now actually set up the cursor, columns, and the list view
changeCursorAndColumns(c, from, to);
- setViewResource(layout);
+ setViewResource(layout);
} else {
// Provide some help for developers instead of just silently discarding
Log.w(LOG_TAG, "Suggestions cursor discarded due to missing required columns.");
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 0a37e81..c1d66f4 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -168,7 +168,8 @@ import android.view.KeyEvent;
* <p><b>Managing focus and knowing if Search is active.</b> The search UI is not a separate
* activity, and when the UI is invoked or dismissed, your activity will not typically be paused,
* resumed, or otherwise notified by the methods defined in
- * <a href="android.app.Activity#ActivityLifecycle">Activity Lifecycle</a>. The search UI is
+ * <a href="{@docRoot}guide/topics/fundamentals.html#actlife">Application Fundamentals:
+ * Activity Lifecycle</a>. The search UI is
* handled in the same way as other system UI elements which may appear from time to time, such as
* notifications, screen locks, or other system alerts:
* <p>When the search UI appears, your activity will lose input focus.
@@ -212,11 +213,11 @@ import android.view.KeyEvent;
* {@link #QUERY getStringExtra(SearchManager.QUERY)}.</li>
* <li>To identify and support your searchable activity, you'll need to
* provide an XML file providing searchability configuration parameters, a reference to that
- * in your searchable activity's <a href="../../../devel/bblocks-manifest.html">manifest</a>
+ * in your searchable activity's <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>
* entry, and an intent-filter declaring that you can
* receive ACTION_SEARCH intents. This is described in more detail in the
* <a href="#SearchabilityMetadata">Searchability Metadata</a> section.</li>
- * <li>Your <a href="../../../devel/bblocks-manifest.html">manifest</a> also needs a metadata entry
+ * <li>Your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> also needs a metadata entry
* providing a global reference to the searchable activity. This is the "glue" directing the search
* UI, when invoked from any of your <i>other</i> activities, to use your application as the
* default search context. This is also described in more detail in the
@@ -359,7 +360,7 @@ import android.view.KeyEvent;
* <li>Implement a Content Provider that provides suggestions. If you already have one, and it
* has access to your suggestions data. If not, you'll have to create one.
* You'll also provide information about your Content Provider in your
- * package's <a href="../../../devel/bblocks-manifest.html">manifest</a>.</li>
+ * package's <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>.</li>
* <li>Update your searchable activity's XML configuration file. There are two categories of
* information used for suggestions:
* <ul><li>The first is (required) data that the search manager will
@@ -634,7 +635,7 @@ import android.view.KeyEvent;
*
* <p><b>Metadata for searchable activity.</b> As with your search implementations described
* above, you must first identify which of your activities is searchable. In the
- * <a href="../../../devel/bblocks-manifest.html">manifest</a> entry for this activity, you must
+ * <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> entry for this activity, you must
* provide two elements:
* <ul><li>An intent-filter specifying that you can receive and process the
* {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} {@link android.content.Intent Intent}.
@@ -643,7 +644,7 @@ import android.view.KeyEvent;
* remaining configuration information for how your application implements search.</li></ul>
*
* <p>Here is a snippet showing the necessary elements in the
- * <a href="../../../devel/bblocks-manifest.html">manifest</a> entry for your searchable activity.
+ * <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> entry for your searchable activity.
* <pre class="prettyprint">
* &lt;!-- Search Activity - searchable --&gt;
* &lt;activity android:name="MySearchActivity"
@@ -746,6 +747,14 @@ import android.view.KeyEvent;
* <a href="../R.attr.html#inputType">inputType</a> attribute.</td>
* <td align="center">No</td>
* </tr>
+ * <tr><th>android:imeOptions</th>
+ * <td>If provided, supplies additional options for the input method.
+ * For most searches, in which free form text is expected, this attribute
+ * need not be provided, and will default to "actionSearch".
+ * Suitable values for this attribute are described in the
+ * <a href="../R.attr.html#imeOptions">imeOptions</a> attribute.</td>
+ * <td align="center">No</td>
+ * </tr>
*
* </tbody>
* </table>
@@ -765,9 +774,8 @@ import android.view.KeyEvent;
* <li>.../res/values/strings.xml</li></ul>
*
* <p>For more complete documentation on this capability, see
- * <a href="../../../devel/resources-i18n.html#AlternateResources">Resources and
- * Internationalization: Supporting Alternate Resources for Alternate Languages and Configurations
- * </a>.
+ * <a href="{@docRoot}guide/topics/resources/resources-i18n.html#AlternateResources">Resources and
+ * Internationalization: Alternate Resources</a>.
*
* <p><b>Metadata for non-searchable activities.</b> Activities which are part of a searchable
* application, but don't implement search itself, require a bit of "glue" in order to cause
@@ -775,7 +783,7 @@ import android.view.KeyEvent;
* provided, then searches from these activities will use the system default search context.
*
* <p>The simplest way to specify this is to add a <i>search reference</i> element to the
- * application entry in the <a href="../../../devel/bblocks-manifest.html">manifest</a> file.
+ * application entry in the <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> file.
* The value of this reference can be either of:
* <ul><li>The name of your searchable activity.
* It is typically prefixed by '.' to indicate that it's in the same package.</li>
@@ -803,7 +811,7 @@ import android.view.KeyEvent;
* to generate search suggestions, you'll need to publish it to the system, and you'll need to
* provide a bit of additional XML metadata in order to configure communications with it.
*
- * <p>First, in your <a href="../../../devel/bblocks-manifest.html">manifest</a>, you'll add the
+ * <p>First, in your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>, you'll add the
* following lines.
* <pre class="prettyprint">
* &lt;!-- Content provider for search suggestions --&gt;
@@ -832,7 +840,7 @@ import android.view.KeyEvent;
* <tbody>
* <tr><th>android:searchSuggestAuthority</th>
* <td>This value must match the authority string provided in the <i>provider</i> section
- * of your <a href="../../../devel/bblocks-manifest.html">manifest</a>.</td>
+ * of your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>.</td>
* <td align="center">Yes</td>
* </tr>
*
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 6c08e75..a6a436f 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -42,12 +42,12 @@ import java.io.PrintWriter;
* thread of their hosting process. This means that, if your service is going
* to do any CPU intensive (such as MP3 playback) or blocking (such as
* networking) operations, it should spawn its own thread in which to do that
- * work. More information on this can be found in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
- * Application Model overview</a>.</p>
+ * work. More information on this can be found in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.</p>
*
* <p>The Service class is an important part of an
- * <a href="{@docRoot}intro/lifecycle.html">application's overall lifecycle</a>.</p>
+ * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">application's overall lifecycle</a>.</p>
*
* <p>Topics covered here:
* <ol>
@@ -79,7 +79,7 @@ import java.io.PrintWriter;
* to the service. The service will remain running as long as the connection
* is established (whether or not the client retains a reference on the
* service's IBinder). Usually the IBinder returned is for a complex
- * interface that has been <a href="{@docRoot}reference/aidl.html">written
+ * interface that has been <a href="{@docRoot}guide/developing/tools/aidl.html">written
* in aidl</a>.
*
* <p>A service can be both started and have connections bound to it. In such
@@ -106,7 +106,7 @@ import java.io.PrintWriter;
* {@link #checkCallingPermission}
* method before executing the implementation of that call.
*
- * <p>See the <a href="{@docRoot}devel/security.html">Security Model</a>
+ * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
* <a name="ProcessLifecycle"></a>
@@ -201,14 +201,14 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
* Return the communication channel to the service. May return null if
* clients can not bind to the service. The returned
* {@link android.os.IBinder} is usually for a complex interface
- * that has been <a href="{@docRoot}reference/aidl.html">described using
+ * that has been <a href="{@docRoot}guide/developing/tools/aidl.html">described using
* aidl</a>.
*
* <p><em>Note that unlike other application components, calls on to the
* IBinder interface returned here may not happen on the main thread
* of the process</em>. More information about this can be found
- * in the <a href="{@docRoot}intro/appmodel.html#Threads">Threading section
- * of the Application Model overview</a>.</p>
+ * in <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.</p>
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
@@ -327,11 +327,15 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
}
/**
- * Print the Service's state into the given stream.
+ * Print the Service's state into the given stream. This gets invoked if
+ * you run "adb shell dumpsys activity service <yourservicename>".
+ * This is distinct from "dumpsys <servicename>", which only works for
+ * named system services and which invokes the {@link IBinder#dump} method
+ * on the {@link IBinder} interface registered with ServiceManager.
*
* @param fd The raw file descriptor that the dump is being sent to.
* @param writer The PrintWriter to which you should dump your state. This will be
- * closed for you after you return.
+ * closed for you after you return.
* @param args additional arguments to the dump request.
*/
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {