summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2015-04-06 20:21:54 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-06 20:21:58 +0000
commit516460819541e483321ef9156e4093d19f123ecc (patch)
treee56340f67bb7ae5ce512618146bef9b5f5e5130f
parentb8a330ebe74f01e05681d24129dd1d595dc23207 (diff)
parentd59a5d59df920d743723521a2afed9de1da3373b (diff)
downloadframeworks_base-516460819541e483321ef9156e4093d19f123ecc.zip
frameworks_base-516460819541e483321ef9156e4093d19f123ecc.tar.gz
frameworks_base-516460819541e483321ef9156e4093d19f123ecc.tar.bz2
Merge "Various fixes and improvements..."
-rw-r--r--api/current.txt6
-rw-r--r--api/system-current.txt6
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java4
-rw-r--r--core/java/android/app/ActivityManager.java41
-rw-r--r--core/java/android/app/ActivityManagerNative.java9
-rw-r--r--core/java/android/app/AppOpsManager.java22
-rw-r--r--core/java/android/app/IActivityManager.java3
-rw-r--r--core/java/android/app/VoiceInteractor.java30
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java10
-rw-r--r--core/java/com/android/internal/app/DumpHeapActivity.java37
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java108
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java9
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java38
-rw-r--r--tests/VoiceInteraction/res/layout/test_interaction.xml53
-rw-r--r--tests/VoiceInteraction/res/values/strings.xml1
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java3
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java11
17 files changed, 333 insertions, 58 deletions
diff --git a/api/current.txt b/api/current.txt
index d79ccbe..cb63af7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3553,6 +3553,7 @@ package android.app {
public class ActivityManager {
method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
method public boolean clearApplicationUserData();
+ method public void clearWatchHeapLimit();
method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
method public android.util.Size getAppTaskThumbnailSize();
method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
@@ -3579,6 +3580,8 @@ package android.app {
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public void setWatchHeapLimit(long);
+ field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
@@ -5434,10 +5437,12 @@ package android.app {
public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable {
ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence);
+ ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence, int);
method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence);
method public int countSynonyms();
method public int describeContents();
method public android.os.Bundle getExtras();
+ method public int getIndex();
method public java.lang.CharSequence getLabel();
method public java.lang.CharSequence getSynonymAt(int);
method public void setExtras(android.os.Bundle);
@@ -28271,6 +28276,7 @@ package android.service.voice {
ctor public VoiceInteractionSession(android.content.Context);
ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
method public void finish();
+ method public android.content.Context getContext();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
method public void hide();
diff --git a/api/system-current.txt b/api/system-current.txt
index e57eee5..7ef0008 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3641,6 +3641,7 @@ package android.app {
public class ActivityManager {
method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
method public boolean clearApplicationUserData();
+ method public void clearWatchHeapLimit();
method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
method public android.util.Size getAppTaskThumbnailSize();
method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
@@ -3668,6 +3669,8 @@ package android.app {
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public void setWatchHeapLimit(long);
+ field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
@@ -5525,10 +5528,12 @@ package android.app {
public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable {
ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence);
+ ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence, int);
method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence);
method public int countSynonyms();
method public int describeContents();
method public android.os.Bundle getExtras();
+ method public int getIndex();
method public java.lang.CharSequence getLabel();
method public java.lang.CharSequence getSynonymAt(int);
method public void setExtras(android.os.Bundle);
@@ -30346,6 +30351,7 @@ package android.service.voice {
ctor public VoiceInteractionSession(android.content.Context);
ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
method public void finish();
+ method public android.content.Context getContext();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
method public void hide();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 0a53371..908d46e 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -1189,12 +1189,12 @@ public class Am extends BaseCommand {
private void runSetWatchHeap() throws Exception {
String proc = nextArgRequired();
String limit = nextArgRequired();
- mAm.setDumpHeapDebugLimit(proc, Long.parseLong(limit));
+ mAm.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null);
}
private void runClearWatchHeap() throws Exception {
String proc = nextArgRequired();
- mAm.setDumpHeapDebugLimit(proc, -1);
+ mAm.setDumpHeapDebugLimit(proc, 0, -1, null);
}
private void runBugReport() throws Exception {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d143f8b..8f125d7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2682,6 +2682,47 @@ public class ActivityManager {
}
/**
+ * Request that the system start watching for the calling process to exceed a pss
+ * size as given here. Once called, the system will look for any occassions where it
+ * sees the associated process with a larger pss size and, when this happens, automatically
+ * pull a heap dump from it and allow the user to share the data. Note that this request
+ * continues running even if the process is killed and restarted. To remove the watch,
+ * use {@link #clearWatchHeapLimit()}.
+ *
+ * <p>This API only work if running on a debuggable (userdebug or eng) build.</p>
+ *
+ * <p>Callers can optionally implement {@link #ACTION_REPORT_HEAP_LIMIT} to directly
+ * handle heap limit reports themselves.</p>
+ *
+ * @param pssSize The size in bytes to set the limit at.
+ */
+ public void setWatchHeapLimit(long pssSize) {
+ try {
+ ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, pssSize,
+ mContext.getPackageName());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Action an app can implement to handle reports from {@link #setWatchHeapLimit(long)}.
+ * If your package has an activity handling this action, it will be launched with the
+ * heap data provided to it the same way as {@link Intent#ACTION_SEND}. Note that to
+ * match the activty must support this action and a MIME type of "*&#47;*".
+ */
+ public static final String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
+
+ /**
+ * Clear a heap watch limit previously set by {@link #setWatchHeapLimit(long)}.
+ */
+ public void clearWatchHeapLimit() {
+ try {
+ ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, 0, null);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* @hide
*/
public void startLockTaskMode(int taskId) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1484af8..be7287f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2427,8 +2427,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String procName = data.readString();
+ int uid = data.readInt();
long maxMemSize = data.readLong();
- setDumpHeapDebugLimit(procName, maxMemSize);
+ String reportPackage = data.readString();
+ setDumpHeapDebugLimit(procName, uid, maxMemSize, reportPackage);
reply.writeNoException();
return true;
}
@@ -5644,12 +5646,15 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
- public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException {
+ public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
+ String reportPackage) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(processName);
+ data.writeInt(uid);
data.writeLong(maxMemSize);
+ data.writeString(reportPackage);
mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4bd2332..381c20c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -208,8 +208,12 @@ public class AppOpsManager {
public static final int OP_ACTIVATE_VPN = 47;
/** @hide Access the WallpaperManagerAPI to write wallpapers. */
public static final int OP_WRITE_WALLPAPER = 48;
+ /** @hide Received the assist structure from an app. */
+ public static final int OP_ASSIST_STRUCTURE = 49;
+ /** @hide Received a screenshot from assist. */
+ public static final int OP_ASSIST_SCREENSHOT = 50;
/** @hide */
- public static final int _NUM_OP = 49;
+ public static final int _NUM_OP = 51;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION =
@@ -288,6 +292,8 @@ public class AppOpsManager {
OP_PROJECT_MEDIA,
OP_ACTIVATE_VPN,
OP_WRITE_WALLPAPER,
+ OP_ASSIST_STRUCTURE,
+ OP_ASSIST_SCREENSHOT,
};
/**
@@ -344,6 +350,8 @@ public class AppOpsManager {
null,
OPSTR_ACTIVATE_VPN,
null,
+ null,
+ null,
};
/**
@@ -400,6 +408,8 @@ public class AppOpsManager {
"PROJECT_MEDIA",
"ACTIVATE_VPN",
"WRITE_WALLPAPER",
+ "ASSIST_STRUCTURE",
+ "ASSIST_SCREENSHOT"
};
/**
@@ -456,6 +466,8 @@ public class AppOpsManager {
null, // no permission for projecting media
null, // no permission for activating vpn
null, // no permission for supporting wallpaper
+ null, // no permission for receiving assist structure
+ null, // no permission for receiving assist screenshot
};
/**
@@ -513,6 +525,8 @@ public class AppOpsManager {
null, //PROJECT_MEDIA
UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN
UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
+ null, // ASSIST_STRUCTURE
+ null, // ASSIST_SCREENSHOT
};
/**
@@ -569,6 +583,8 @@ public class AppOpsManager {
false, //PROJECT_MEDIA
false, //ACTIVATE_VPN
false, //WALLPAPER
+ false, //ASSIST_STRUCTURE
+ false, //ASSIST_SCREENSHOT
};
/**
@@ -624,6 +640,8 @@ public class AppOpsManager {
AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
};
/**
@@ -683,6 +701,8 @@ public class AppOpsManager {
false,
false,
false,
+ false,
+ false,
};
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index d794aa3..e20b0da 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -482,7 +482,8 @@ public interface IActivityManager extends IInterface {
public void systemBackupRestored() throws RemoteException;
public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
- public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException;
+ public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
+ String reportPackage) throws RemoteException;
public void dumpHeapFinished(String path) throws RemoteException;
public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake)
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index da7bb05..7acf5f0 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -103,9 +103,9 @@ public class VoiceInteractor {
request = pullRequest((IVoiceInteractorRequest)args.arg1, true);
if (DEBUG) Log.d(TAG, "onCompleteVoice: req="
+ ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
- + " result=" + args.arg1);
+ + " result=" + args.arg2);
if (request != null) {
- ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg1);
+ ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg2);
request.clear();
}
break;
@@ -297,6 +297,7 @@ public class VoiceInteractor {
*/
public static final class Option implements Parcelable {
final CharSequence mLabel;
+ final int mIndex;
ArrayList<CharSequence> mSynonyms;
Bundle mExtras;
@@ -308,6 +309,21 @@ public class VoiceInteractor {
*/
public Option(CharSequence label) {
mLabel = label;
+ mIndex = -1;
+ }
+
+ /**
+ * Creates an option that a user can select with their voice by matching the label
+ * or one of several synonyms.
+ * @param label The label that will both be matched against what the user speaks
+ * and displayed visually.
+ * @param index The location of this option within the overall set of options.
+ * Can be used to help identify which the option when it is returned from the
+ * voice interactor.
+ */
+ public Option(CharSequence label, int index) {
+ mLabel = label;
+ mIndex = index;
}
/**
@@ -328,6 +344,14 @@ public class VoiceInteractor {
return mLabel;
}
+ /**
+ * Return the index that was supplied in the constructor.
+ * If the option was constructed without an index, -1 is returned.
+ */
+ public int getIndex() {
+ return mIndex;
+ }
+
public int countSynonyms() {
return mSynonyms != null ? mSynonyms.size() : 0;
}
@@ -356,6 +380,7 @@ public class VoiceInteractor {
Option(Parcel in) {
mLabel = in.readCharSequence();
+ mIndex = in.readInt();
mSynonyms = in.readCharSequenceList();
mExtras = in.readBundle();
}
@@ -368,6 +393,7 @@ public class VoiceInteractor {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharSequence(mLabel);
+ dest.writeInt(mIndex);
dest.writeCharSequenceList(mSynonyms);
dest.writeBundle(mExtras);
}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 4c31f80..20d7079 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -520,6 +520,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
mCallbacks, true);
}
+ public Context getContext() {
+ return mContext;
+ }
+
Request newRequest(IVoiceInteractorCallback callback) {
synchronized (this) {
Request req = new Request(callback, this);
@@ -832,6 +836,12 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
return false;
}
+ /**
+ * Called when the user presses the back button while focus is in the session UI. Note
+ * that this will only happen if the session UI has requested input focus in its window;
+ * otherwise, the back key will go to whatever window has focus and do whatever behavior
+ * it normally has there.
+ */
public void onBackPressed() {
hide();
}
diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java
index 7e70b0c..0ce501e 100644
--- a/core/java/com/android/internal/app/DumpHeapActivity.java
+++ b/core/java/com/android/internal/app/DumpHeapActivity.java
@@ -17,13 +17,16 @@
package com.android.internal.app;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.DebugUtils;
+import android.util.Slog;
/**
* This activity is displayed when the system has collected a heap dump from
@@ -34,6 +37,8 @@ public class DumpHeapActivity extends Activity {
public static final String KEY_PROCESS = "process";
/** The size limit the process reached */
public static final String KEY_SIZE = "size";
+ /** Optional name of package to directly launch */
+ public static final String KEY_DIRECT_LAUNCH = "direct_launch";
// Broadcast action to determine when to delete the current dump heap data.
public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP";
@@ -54,6 +59,28 @@ public class DumpHeapActivity extends Activity {
mProcess = getIntent().getStringExtra(KEY_PROCESS);
mSize = getIntent().getLongExtra(KEY_SIZE, 0);
+
+ String directLaunch = getIntent().getStringExtra(KEY_DIRECT_LAUNCH);
+ if (directLaunch != null) {
+ Intent intent = new Intent(ActivityManager.ACTION_REPORT_HEAP_LIMIT);
+ intent.setPackage(directLaunch);
+ ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
+ intent.setClipData(clip);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setType(clip.getDescription().getMimeType(0));
+ intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI);
+ try {
+ startActivity(intent);
+ scheduleDelete();
+ mHandled = true;
+ finish();
+ return;
+ } catch (ActivityNotFoundException e) {
+ Slog.i("DumpHeapActivity", "Unable to direct launch to " + directLaunch
+ + ": " + e.getMessage());
+ }
+ }
+
AlertDialog.Builder b = new AlertDialog.Builder(this,
android.R.style.Theme_Material_Light_Dialog_Alert);
b.setTitle(com.android.internal.R.string.dump_heap_title);
@@ -71,9 +98,7 @@ public class DumpHeapActivity extends Activity {
@Override
public void onClick(DialogInterface dialog, int which) {
mHandled = true;
- Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
- broadcast.putExtra(EXTRA_DELAY_DELETE, true);
- sendBroadcast(broadcast);
+ scheduleDelete();
Intent intent = new Intent(Intent.ACTION_SEND);
ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
intent.setClipData(clip);
@@ -88,6 +113,12 @@ public class DumpHeapActivity extends Activity {
mDialog = b.show();
}
+ void scheduleDelete() {
+ Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
+ broadcast.putExtra(EXTRA_DELAY_DELETE, true);
+ sendBroadcast(broadcast);
+ }
+
@Override
protected void onStop() {
super.onStop();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cf51004..c4c81be 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1124,7 +1124,7 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean mAutoStopProfiler = false;
int mProfileType = 0;
String mOpenGlTraceApp = null;
- final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>();
+ final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
String mMemWatchDumpProcName;
String mMemWatchDumpFile;
int mMemWatchDumpPid;
@@ -1830,11 +1830,21 @@ public final class ActivityManagerService extends ActivityManagerNative
final String procName;
final int uid;
final long memLimit;
+ final String reportPackage;
synchronized (ActivityManagerService.this) {
procName = mMemWatchDumpProcName;
uid = mMemWatchDumpUid;
- Long limit = mMemWatchProcesses.get(procName);
- memLimit = limit != null ? limit : 0;
+ Pair<Long, String> val = mMemWatchProcesses.get(procName, uid);
+ if (val == null) {
+ val = mMemWatchProcesses.get(procName, 0);
+ }
+ if (val != null) {
+ memLimit = val.first;
+ reportPackage = val.second;
+ } else {
+ memLimit = 0;
+ reportPackage = null;
+ }
}
if (procName == null) {
return;
@@ -1867,6 +1877,9 @@ public final class ActivityManagerService extends ActivityManagerNative
intent.setClassName("android", DumpHeapActivity.class.getName());
intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
+ if (reportPackage != null) {
+ intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
+ }
int userId = UserHandle.getUserId(uid);
notification.setLatestEventInfo(mContext, text,
mContext.getText(R.string.dump_heap_notification_detail),
@@ -2474,11 +2487,19 @@ public final class ActivityManagerService extends ActivityManagerNative
final void setFocusedActivityLocked(ActivityRecord r, String reason) {
if (r != null && mFocusedActivity != r) {
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
+ ActivityRecord last = mFocusedActivity;
mFocusedActivity = r;
if (r.task != null && r.task.voiceInteractor != null) {
startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
} else {
finishRunningVoiceLocked();
+ if (last != null && last.task.voiceSession != null) {
+ // We had been in a voice interaction session, but now focused has
+ // move to something different. Just finish the session, we can't
+ // return to it and retain the proper state and synchronization with
+ // the voice interaction service.
+ finishVoiceTask(last.task.voiceSession);
+ }
}
if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
mWindowManager.setFocusedApp(r.appToken, true);
@@ -12855,16 +12876,28 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
}
}
- if (mMemWatchProcesses.size() > 0) {
+ if (mMemWatchProcesses.getMap().size() > 0) {
pw.println(" Mem watch processes:");
- for (int i=0; i<mMemWatchProcesses.size(); i++) {
- if (needSep) {
- pw.println();
- needSep = false;
+ final ArrayMap<String, SparseArray<Pair<Long, String>>> procs
+ = mMemWatchProcesses.getMap();
+ for (int i=0; i<procs.size(); i++) {
+ final String proc = procs.keyAt(i);
+ final SparseArray<Pair<Long, String>> uids = procs.valueAt(i);
+ for (int j=0; j<uids.size(); j++) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(" ").append(proc).append('/');
+ UserHandle.formatUid(sb, uids.keyAt(j));
+ Pair<Long, String> val = uids.valueAt(i);
+ sb.append(": "); DebugUtils.sizeValueToString(val.first, sb);
+ if (val.second != null) {
+ sb.append(", report to ").append(val.second);
+ }
+ pw.println(sb.toString());
}
- pw.print(" "); pw.print(mMemWatchProcesses.keyAt(i));
- pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i));
- pw.println();
}
pw.print(" mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
pw.print(" mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
@@ -17389,7 +17422,18 @@ public final class ActivityManagerService extends ActivityManagerNative
proc.lastCachedPss = pss;
}
- Long check = mMemWatchProcesses.get(proc.processName);
+ final SparseArray<Pair<Long, String>> watchUids
+ = mMemWatchProcesses.getMap().get(proc.processName);
+ Long check = null;
+ if (watchUids != null) {
+ Pair<Long, String> val = watchUids.get(proc.uid);
+ if (val == null) {
+ val = watchUids.get(0);
+ }
+ if (val != null) {
+ check = val.first;
+ }
+ }
if (check != null) {
if ((pss * 1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
@@ -17425,7 +17469,8 @@ public final class ActivityManagerService extends ActivityManagerNative
IApplicationThread thread = myProc.thread;
if (thread != null) {
try {
- if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting dump heap from "
+ if (true || DEBUG_PSS) Slog.d(TAG_PSS,
+ "Requesting dump heap from "
+ myProc + " to " + heapdumpFile);
thread.dumpHeap(true, heapdumpFile.toString(), fd);
} catch (RemoteException e) {
@@ -18660,15 +18705,38 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public void setDumpHeapDebugLimit(String processName, long maxMemSize) {
- enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
- "setDumpHeapDebugLimit()");
+ public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
+ String reportPackage) {
+ if (processName != null) {
+ enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
+ "setDumpHeapDebugLimit()");
+ } else {
+ if (!Build.IS_DEBUGGABLE) {
+ throw new SecurityException("Not running a debuggable build");
+ }
+ synchronized (mPidsSelfLocked) {
+ ProcessRecord proc = mPidsSelfLocked.get(Binder.getCallingPid());
+ if (proc == null) {
+ throw new SecurityException("No process found for calling pid "
+ + Binder.getCallingPid());
+ }
+ processName = proc.processName;
+ uid = proc.uid;
+ if (reportPackage != null && !proc.pkgList.containsKey(reportPackage)) {
+ throw new SecurityException("Package " + reportPackage + " is not running in "
+ + proc);
+ }
+ }
+ }
synchronized (this) {
if (maxMemSize > 0) {
- mMemWatchProcesses.put(processName, maxMemSize);
- mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+ mMemWatchProcesses.put(processName, uid, new Pair(maxMemSize, reportPackage));
} else {
- mMemWatchProcesses.remove(processName);
+ if (uid != 0) {
+ mMemWatchProcesses.remove(processName, uid);
+ } else {
+ mMemWatchProcesses.getMap().remove(processName);
+ }
}
}
}
@@ -18686,7 +18754,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " does not match last path " + mMemWatchDumpFile);
return;
}
- if (DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path);
+ if (true || DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path);
mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 1aa0d0b..bca757b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -145,7 +145,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
}
public boolean hideSessionLocked(int callingPid, int callingUid) {
- return mActiveSession.hideLocked();
+ if (mActiveSession != null) {
+ return mActiveSession.hideLocked();
+ }
+ return false;
}
public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
@@ -165,6 +168,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
Slog.w(TAG, "startVoiceActivity does not match active session");
return ActivityManager.START_CANCELED;
}
+ if (!mActiveSession.mShown) {
+ Slog.w(TAG, "startVoiceActivity not allowed on hidden session");
+ return ActivityManager.START_CANCELED;
+ }
intent = new Intent(intent);
intent.addCategory(Intent.CATEGORY_VOICE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 73c7363..607df2d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -18,6 +18,7 @@ package com.android.server.voiceinteraction;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.AppOpsManager;
import android.app.AssistContent;
import android.app.IActivityManager;
import android.content.ClipData;
@@ -62,6 +63,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
final int mCallingUid;
final IActivityManager mAm;
final IWindowManager mIWindowManager;
+ final AppOpsManager mAppOps;
final IBinder mPermissionOwner;
boolean mShown;
Bundle mShowArgs;
@@ -148,6 +150,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
mAm = ActivityManagerNative.getDefault();
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
+ mAppOps = context.getSystemService(AppOpsManager.class);
IBinder permOwner = null;
try {
permOwner = mAm.newUriPermissionOwner("voicesession:"
@@ -159,7 +162,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
mBindIntent.setComponent(mSessionComponentName);
mBound = mContext.bindServiceAsUser(mBindIntent, this,
- Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
+ Context.BIND_AUTO_CREATE|Context.BIND_WAIVE_PRIORITY
+ |Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
if (mBound) {
try {
mIWindowManager.addWindowToken(mToken,
@@ -186,19 +190,31 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
mShowFlags = flags;
mHaveAssistData = false;
if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
- try {
- mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
- mAssistReceiver);
- } catch (RemoteException e) {
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
+ mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) {
+ try {
+ mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+ mAssistReceiver);
+ } catch (RemoteException e) {
+ }
+ } else {
+ mHaveAssistData = true;
+ mAssistData = null;
}
} else {
mAssistData = null;
}
mHaveScreenshot = false;
if ((flags&VoiceInteractionService.START_WITH_SCREENSHOT) != 0) {
- try {
- mIWindowManager.requestAssistScreenshot(mScreenshotReceiver);
- } catch (RemoteException e) {
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid,
+ mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) {
+ try {
+ mIWindowManager.requestAssistScreenshot(mScreenshotReceiver);
+ } catch (RemoteException e) {
+ }
+ } else {
+ mHaveScreenshot = true;
+ mScreenshot = null;
}
} else {
mScreenshot = null;
@@ -335,6 +351,12 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
mUser);
} catch (RemoteException e) {
}
+ if (mSession != null) {
+ try {
+ mAm.finishVoiceTask(mSession);
+ } catch (RemoteException e) {
+ }
+ }
}
if (mFullyBound) {
mContext.unbindService(mFullConnection);
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
index 8c8151d..6209bd0 100644
--- a/tests/VoiceInteraction/res/layout/test_interaction.xml
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -34,32 +34,49 @@
android:textAppearance="?android:attr/textAppearanceMedium"
/>
- <Button android:id="@+id/complete"
- android:layout_width="wrap_content"
+ <LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
- android:text="@string/completeVoice"
- />
+ android:orientation="horizontal">
+
+ <Button android:id="@+id/complete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/completeVoice"
+ />
+
+ <Button android:id="@+id/abort"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/abortVoice"
+ />
+
+ <Button android:id="@+id/pick"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/pickVoice"
+ />
+
+ </LinearLayout>
- <Button android:id="@+id/pick"
- android:layout_width="wrap_content"
+ <LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
- android:text="@string/pickVoice"
+ android:layout_marginBottom="16dp"
+ android:orientation="horizontal">
+
+ <Button android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/cancelVoice"
/>
- <Button android:id="@+id/abort"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:text="@string/abortVoice"
+ <Button android:id="@+id/jump"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/jumpOut"
/>
- <Button android:id="@+id/cancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:text="@string/cancelVoice"
- />
+ </LinearLayout>
</LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index 942c931..6289929 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -25,5 +25,6 @@
<string name="completeVoice">Complete Voice</string>
<string name="pickVoice">Pick Voice</string>
<string name="cancelVoice">Cancel</string>
+ <string name="jumpOut">Jump out</string>
</resources>
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index ec727c4..3c5c201 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -16,6 +16,7 @@
package com.android.test.voiceinteraction;
+import android.app.ActivityManager;
import android.app.AssistContent;
import android.app.AssistStructure;
import android.app.VoiceInteractor;
@@ -69,6 +70,8 @@ public class MainInteractionSession extends VoiceInteractionSession
@Override
public void onCreate(Bundle args, int startFlags) {
super.onCreate(args);
+ ActivityManager am = getContext().getSystemService(ActivityManager.class);
+ am.setWatchHeapLimit(40*1024*1024);
}
@Override
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index e195c30..9d24c59 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -19,6 +19,7 @@ package com.android.test.voiceinteraction;
import android.app.Activity;
import android.app.VoiceInteractor;
import android.content.ComponentName;
+import android.content.Intent;
import android.os.Bundle;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
@@ -37,6 +38,7 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
Button mAbortButton;
Button mCompleteButton;
Button mPickButton;
+ Button mJumpOutButton;
Button mCancelButton;
@Override
@@ -64,6 +66,8 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
mCompleteButton.setOnClickListener(this);
mPickButton = (Button)findViewById(R.id.pick);
mPickButton.setOnClickListener(this);
+ mJumpOutButton = (Button)findViewById(R.id.jump);
+ mJumpOutButton.setOnClickListener(this);
mCancelButton = (Button)findViewById(R.id.cancel);
mCancelButton.setOnClickListener(this);
@@ -165,6 +169,13 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
}
};
mInteractor.submitRequest(req);
+ } else if (v == mJumpOutButton) {
+ Log.i(TAG, "Jump out");
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setComponent(new ComponentName(this, VoiceInteractionMain.class));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
} else if (v == mCancelButton && mCurrentRequest != null) {
Log.i(TAG, "Cancel request");
mCurrentRequest.cancel();