summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java6
-rw-r--r--core/java/android/app/PendingIntent.java2
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java6
-rw-r--r--core/java/android/view/WindowManager.java18
-rw-r--r--core/java/com/android/internal/view/IInputMethod.aidl26
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--docs/html/index.jd5
-rw-r--r--packages/Shell/Android.mk2
-rw-r--r--packages/Shell/AndroidManifest.xml29
-rw-r--r--packages/Shell/res/layout/confirm_repeat.xml37
-rw-r--r--packages/Shell/res/values/strings.xml10
-rw-r--r--packages/Shell/res/xml/file_provider_paths.xml3
-rw-r--r--packages/Shell/src/com/android/shell/BugreportPrefs.java45
-rw-r--r--packages/Shell/src/com/android/shell/BugreportReceiver.java198
-rw-r--r--packages/Shell/src/com/android/shell/BugreportWarningActivity.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/ImageWallpaper.java19
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java19
17 files changed, 467 insertions, 36 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 9fa7dbb7e91d..1c02960deeca 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -63,6 +63,7 @@ public class Am {
private int mRepeat = 0;
private int mUserId;
+ private String mReceiverPermission;
private String mProfileFile;
@@ -332,6 +333,8 @@ public class Am {
mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES;
} else if (opt.equals("--user")) {
mUserId = parseUserArg(nextArgRequired());
+ } else if (opt.equals("--receiver-permission")) {
+ mReceiverPermission = nextArgRequired();
} else {
System.err.println("Error: Unknown option: " + opt);
return null;
@@ -608,7 +611,7 @@ public class Am {
Intent intent = makeIntent(UserHandle.USER_ALL);
IntentReceiver receiver = new IntentReceiver();
System.out.println("Broadcasting: " + intent);
- mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null,
+ mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission,
android.app.AppOpsManager.OP_NONE, true, false, mUserId);
receiver.waitForFinish();
}
@@ -1408,6 +1411,7 @@ public class Am {
"am broadcast: send a broadcast Intent. Options are:\n" +
" --user <USER_ID> | all | current: Specify which user to send to; if not\n" +
" specified then send to all users.\n" +
+ " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" +
"\n" +
"am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" +
" is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" +
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 37804e9103a5..20114cc52802 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -261,6 +261,7 @@ public final class PendingIntent implements Parcelable {
context.getContentResolver()) : null;
try {
intent.setAllowFds(false);
+ intent.migrateExtraStreamToClipData();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -285,6 +286,7 @@ public final class PendingIntent implements Parcelable {
context.getContentResolver()) : null;
try {
intent.setAllowFds(false);
+ intent.migrateExtraStreamToClipData();
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 2d67875c6084..d59c7b819df3 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -284,6 +284,12 @@ class IInputMethodWrapper extends IInputMethod.Stub
flags, resultReceiver));
}
+ @Override
+ public void removeSoftInputMessages() {
+ mCaller.removeMessages(DO_SHOW_SOFT_INPUT);
+ mCaller.removeMessages(DO_HIDE_SOFT_INPUT);
+ }
+
public void changeInputMethodSubtype(InputMethodSubtype subtype) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CHANGE_INPUTMETHOD_SUBTYPE,
subtype));
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 792188bb501a..96ef0b41ef69 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -272,7 +272,7 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
/**
- * Window type: window for showing media (e.g. video). These windows
+ * Window type: window for showing media (such as video). These windows
* are displayed behind their attached window.
*/
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1;
@@ -584,14 +584,14 @@ public interface WindowManager extends ViewManager {
/** Window flag: this window can never receive touch events. */
public static final int FLAG_NOT_TOUCHABLE = 0x00000010;
- /** Window flag: Even when this window is focusable (its
- * {@link #FLAG_NOT_FOCUSABLE is not set), allow any pointer events
+ /** Window flag: even when this window is focusable (its
+ * {@link #FLAG_NOT_FOCUSABLE} is not set), allow any pointer events
* outside of the window to be sent to the windows behind it. Otherwise
* it will consume all pointer events itself, regardless of whether they
* are inside of the window. */
public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;
- /** Window flag: When set, if the device is asleep when the touch
+ /** Window flag: when set, if the device is asleep when the touch
* screen is pressed, you will receive this first touch event. Usually
* the first touch event is consumed by the system since the user can
* not see what they are pressing on.
@@ -603,7 +603,7 @@ public interface WindowManager extends ViewManager {
public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;
/** Window flag: place the window within the entire screen, ignoring
- * decorations around the border (a.k.a. the status bar). The
+ * decorations around the border (such as the status bar). The
* window must correctly position its contents to take the screen
* decoration into account. This flag is normally set for you
* by Window as described in {@link Window#setFlags}. */
@@ -613,7 +613,7 @@ public interface WindowManager extends ViewManager {
public static final int FLAG_LAYOUT_NO_LIMITS = 0x00000200;
/**
- * Window flag: Hide all screen decorations (e.g. status bar) while
+ * Window flag: hide all screen decorations (such as the status bar) while
* this window is displayed. This allows the window to use the entire
* display space for itself -- the status bar will be hidden when
* an app window with this flag set is on the top layer.
@@ -631,8 +631,8 @@ public interface WindowManager extends ViewManager {
*/
public static final int FLAG_FULLSCREEN = 0x00000400;
- /** Window flag: Override {@link #FLAG_FULLSCREEN and force the
- * screen decorations (such as status bar) to be shown. */
+ /** Window flag: override {@link #FLAG_FULLSCREEN} and force the
+ * screen decorations (such as the status bar) to be shown. */
public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;
/** Window flag: turn on dithering when compositing this window to
@@ -641,7 +641,7 @@ public interface WindowManager extends ViewManager {
@Deprecated
public static final int FLAG_DITHER = 0x00001000;
- /** Window flag: Treat the content of the window as secure, preventing
+ /** Window flag: treat the content of the window as secure, preventing
* it from appearing in screenshots or from being viewed on non-secure
* displays.
*
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index c7fcab8ecd29..c2a7fc73b0c3 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -33,26 +33,28 @@ import com.android.internal.view.IInputMethodSession;
* Service).
* {@hide}
*/
-oneway interface IInputMethod {
- void attachToken(IBinder token);
+interface IInputMethod {
+ oneway void attachToken(IBinder token);
- void bindInput(in InputBinding binding);
+ oneway void bindInput(in InputBinding binding);
- void unbindInput();
+ oneway void unbindInput();
- void startInput(in IInputContext inputContext, in EditorInfo attribute);
+ oneway void startInput(in IInputContext inputContext, in EditorInfo attribute);
- void restartInput(in IInputContext inputContext, in EditorInfo attribute);
+ oneway void restartInput(in IInputContext inputContext, in EditorInfo attribute);
- void createSession(IInputMethodCallback callback);
+ oneway void createSession(IInputMethodCallback callback);
- void setSessionEnabled(IInputMethodSession session, boolean enabled);
+ oneway void setSessionEnabled(IInputMethodSession session, boolean enabled);
- void revokeSession(IInputMethodSession session);
+ oneway void revokeSession(IInputMethodSession session);
- void showSoftInput(int flags, in ResultReceiver resultReceiver);
+ oneway void showSoftInput(int flags, in ResultReceiver resultReceiver);
- void hideSoftInput(int flags, in ResultReceiver resultReceiver);
+ oneway void hideSoftInput(int flags, in ResultReceiver resultReceiver);
- void changeInputMethodSubtype(in InputMethodSubtype subtype);
+ void removeSoftInputMessages();
+
+ oneway void changeInputMethodSubtype(in InputMethodSubtype subtype);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8a53cc35ca7d..5a1c0f89fd5d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -169,6 +169,7 @@
<protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
<protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
<protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
+ <protected-broadcast android:name="android.intent.action.BUGREPORT_FINISHED" />
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
diff --git a/docs/html/index.jd b/docs/html/index.jd
index f2df7beccc90..ec0469c51de5 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -19,12 +19,11 @@ page.metaDescription=The official site for Android developers. Provides the Andr
<div class="content-right col-5">
<h1>Google I/O 2013</h1>
<p>Android will be at Google I/O on May 15-17, 2013, with sessions covering a variety of topics
- such as design, performance, and how to extend your app with the latest Android features.
- Registration opens on March 13, 2013 at 7:00 AM PDT (GMT-7).</p>
+ such as design, performance, and how to extend your app with the latest Android features.</p>
<p>For more information about event details and planned sessions,
stay tuned to <a
href="http://google.com/+GoogleDevelopers">+Google Developers</a>.</p>
- <p><a href="https://developers.google.com/events/io/register" class="button">Register here</a></p>
+ <p><a href="https://developers.google.com/events/io/" class="button">Learn more</a></p>
</div>
</li>
<li class="item carousel-home">
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index f993ab542fa1..fc4c0f57475d 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -5,6 +5,8 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
LOCAL_PACKAGE_NAME := Shell
LOCAL_CERTIFICATE := platform
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b42db453e69e..ffb4c2026291 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -68,7 +68,32 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
-
- <application android:hasCode="false" android:label="@string/app_label">
+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+
+ <application android:label="@string/app_label">
+ <provider
+ android:name="android.support.v4.content.FileProvider"
+ android:authorities="com.android.shell"
+ android:grantUriPermissions="true"
+ android:exported="false">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_provider_paths" />
+ </provider>
+
+ <activity
+ android:name=".BugreportWarningActivity"
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:exported="false" />
+
+ <receiver
+ android:name=".BugreportReceiver"
+ android:permission="android.permission.DUMP">
+ <intent-filter>
+ <action android:name="android.intent.action.BUGREPORT_FINISHED" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/packages/Shell/res/layout/confirm_repeat.xml b/packages/Shell/res/layout/confirm_repeat.xml
new file mode 100644
index 000000000000..dc250d68754d
--- /dev/null
+++ b/packages/Shell/res/layout/confirm_repeat.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:paddingTop="8dip"
+ android:paddingBottom="16dip"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bugreport_confirm"
+ android:paddingBottom="16dip"
+ style="?android:attr/textAppearanceMedium" />
+ <CheckBox
+ android:id="@android:id/checkbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bugreport_confirm_repeat" />
+</LinearLayout>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 50610d586187..e5606c78ec06 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -16,4 +16,14 @@
<resources>
<string name="app_label">Shell</string>
+
+ <!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] -->
+ <string name="bugreport_finished_title">Bug report captured</string>
+ <!-- Text of notification indicating that touching will share the captured bugreport. [CHAR LIMIT=100] -->
+ <string name="bugreport_finished_text">Touch to share your bug report</string>
+
+ <!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
+ <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people you trust.</string>
+ <!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
+ <string name="bugreport_confirm_repeat">Show this message next time</string>
</resources>
diff --git a/packages/Shell/res/xml/file_provider_paths.xml b/packages/Shell/res/xml/file_provider_paths.xml
new file mode 100644
index 000000000000..225c7571e7e2
--- /dev/null
+++ b/packages/Shell/res/xml/file_provider_paths.xml
@@ -0,0 +1,3 @@
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+ <files-path name="bugreports" path="bugreports/" />
+</paths>
diff --git a/packages/Shell/src/com/android/shell/BugreportPrefs.java b/packages/Shell/src/com/android/shell/BugreportPrefs.java
new file mode 100644
index 000000000000..3748e89c0598
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/BugreportPrefs.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+/**
+ * Preferences related to bug reports.
+ */
+public class BugreportPrefs {
+ private static final String PREFS_BUGREPORT = "bugreports";
+
+ private static final String KEY_WARNING_STATE = "warning-state";
+
+ public static final int STATE_UNKNOWN = 0;
+ public static final int STATE_SHOW = 1;
+ public static final int STATE_HIDE = 2;
+
+ public static int getWarningState(Context context, int def) {
+ final SharedPreferences prefs = context.getSharedPreferences(
+ PREFS_BUGREPORT, Context.MODE_PRIVATE);
+ return prefs.getInt(KEY_WARNING_STATE, def);
+ }
+
+ public static void setWarningState(Context context, int value) {
+ final SharedPreferences prefs = context.getSharedPreferences(
+ PREFS_BUGREPORT, Context.MODE_PRIVATE);
+ prefs.edit().putInt(KEY_WARNING_STATE, value).apply();
+ }
+}
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
new file mode 100644
index 000000000000..3b1ebf49490b
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.getWarningState;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.SystemProperties;
+import android.support.v4.content.FileProvider;
+import android.util.Log;
+import android.util.Patterns;
+
+import com.google.android.collect.Lists;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Receiver that handles finished bugreports, usually by attaching them to an
+ * {@link Intent#ACTION_SEND}.
+ */
+public class BugreportReceiver extends BroadcastReceiver {
+ private static final String TAG = "Shell";
+
+ private static final String AUTHORITY = "com.android.shell";
+
+ private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
+ private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+
+ /**
+ * Number of bugreports to retain before deleting the oldest; 4 reports and
+ * 4 screenshots are roughly 17MB of disk space.
+ */
+ private static final int NUM_OLD_FILES = 8;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+ final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+
+ // Files are kept on private storage, so turn into Uris that we can
+ // grant temporary permissions for.
+ final Uri bugreportUri = FileProvider.getUriForFile(context, AUTHORITY, bugreportFile);
+ final Uri screenshotUri = FileProvider.getUriForFile(context, AUTHORITY, screenshotFile);
+
+ Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
+ Intent notifIntent;
+
+ // Send through warning dialog by default
+ if (getWarningState(context, STATE_SHOW) == STATE_SHOW) {
+ notifIntent = buildWarningIntent(context, sendIntent);
+ } else {
+ notifIntent = sendIntent;
+ }
+ notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ final Notification.Builder builder = new Notification.Builder(context);
+ builder.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb);
+ builder.setContentTitle(context.getString(R.string.bugreport_finished_title));
+ builder.setContentText(context.getString(R.string.bugreport_finished_text));
+ builder.setContentIntent(PendingIntent.getActivity(
+ context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT));
+ builder.setAutoCancel(true);
+ NotificationManager.from(context).notify(TAG, 0, builder.build());
+
+ // Clean up older bugreports in background
+ final PendingResult result = goAsync();
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ deleteOlderFiles(bugreportFile.getParentFile(), NUM_OLD_FILES);
+ result.finish();
+ return null;
+ }
+ }.execute();
+ }
+
+ private static Intent buildWarningIntent(Context context, Intent sendIntent) {
+ final Intent intent = new Intent(context, BugreportWarningActivity.class);
+ intent.putExtra(Intent.EXTRA_INTENT, sendIntent);
+ return intent;
+ }
+
+ /**
+ * Build {@link Intent} that can be used to share the given bugreport.
+ */
+ private static Intent buildSendIntent(Context context, Uri bugreportUri, Uri screenshotUri) {
+ final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setType("application/vnd.android.bugreport");
+
+ intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
+ intent.putExtra(Intent.EXTRA_TEXT, SystemProperties.get("ro.build.description"));
+
+ final ArrayList<Uri> attachments = Lists.newArrayList(bugreportUri, screenshotUri);
+ intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
+
+ final Account sendToAccount = findSendToAccount(context);
+ if (sendToAccount != null) {
+ intent.putExtra(Intent.EXTRA_EMAIL, new String[] { sendToAccount.name });
+ }
+
+ return intent;
+ }
+
+ /**
+ * Find the best matching {@link Account} based on build properties.
+ */
+ private static Account findSendToAccount(Context context) {
+ final AccountManager am = (AccountManager) context.getSystemService(
+ Context.ACCOUNT_SERVICE);
+
+ String preferredDomain = SystemProperties.get("sendbug.preferred.domain");
+ if (!preferredDomain.startsWith("@")) {
+ preferredDomain = "@" + preferredDomain;
+ }
+
+ final Account[] accounts = am.getAccounts();
+ Account foundAccount = null;
+ for (Account account : accounts) {
+ if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
+ if (!preferredDomain.isEmpty()) {
+ // if we have a preferred domain and it matches, return; otherwise keep
+ // looking
+ if (account.name.endsWith(preferredDomain)) {
+ return account;
+ } else {
+ foundAccount = account;
+ }
+ // if we don't have a preferred domain, just return since it looks like
+ // an email address
+ } else {
+ return account;
+ }
+ }
+ }
+ return foundAccount;
+ }
+
+ /**
+ * Delete the oldest files in given directory until only the requested
+ * number remain.
+ */
+ private static void deleteOlderFiles(File dir, int retainNum) {
+ final File[] files = dir.listFiles();
+ if (files == null) return;
+
+ Arrays.sort(files, new ModifiedComparator());
+ for (int i = retainNum; i < files.length; i++) {
+ Log.d(TAG, "Deleting old file " + files[i]);
+ files[i].delete();
+ }
+ }
+
+ private static class ModifiedComparator implements Comparator<File> {
+ @Override
+ public int compare(File lhs, File rhs) {
+ return (int) (rhs.lastModified() - lhs.lastModified());
+ }
+ }
+
+ private static File getFileExtra(Intent intent, String key) {
+ final String path = intent.getStringExtra(key);
+ if (path != null) {
+ return new File(path);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
new file mode 100644
index 000000000000..a1d879af2025
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
+import static com.android.shell.BugreportPrefs.getWarningState;
+import static com.android.shell.BugreportPrefs.setWarningState;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.widget.CheckBox;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+/**
+ * Dialog that warns about contents of a bugreport.
+ */
+public class BugreportWarningActivity extends AlertActivity
+ implements DialogInterface.OnClickListener {
+
+ private Intent mSendIntent;
+ private CheckBox mConfirmRepeat;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mSendIntent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
+
+ // We need to touch the extras to unpack them so they get migrated to
+ // ClipData correctly.
+ mSendIntent.hasExtra(Intent.EXTRA_STREAM);
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mView = LayoutInflater.from(this).inflate(R.layout.confirm_repeat, null);
+ ap.mPositiveButtonText = getString(android.R.string.ok);
+ ap.mNegativeButtonText = getString(android.R.string.cancel);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ mConfirmRepeat = (CheckBox) ap.mView.findViewById(android.R.id.checkbox);
+ mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) == STATE_SHOW);
+
+ setupAlert();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ // Remember confirm state, and launch target
+ setWarningState(this, mConfirmRepeat.isChecked() ? STATE_SHOW : STATE_HIDE);
+ startActivity(mSendIntent);
+ }
+
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index f3eecf2dda99..627235f1e03b 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -627,10 +627,26 @@ public class ImageWallpaper extends WallpaperService {
}
mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+ if (mEglContext == EGL_NO_CONTEXT) {
+ throw new RuntimeException("createContext failed " +
+ GLUtils.getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ int attribs[] = {
+ EGL_WIDTH, 1,
+ EGL_HEIGHT, 1,
+ EGL_NONE
+ };
+ EGLSurface tmpSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
+ mEgl.eglMakeCurrent(mEglDisplay, tmpSurface, tmpSurface, mEglContext);
int[] maxSize = new int[1];
Rect frame = surfaceHolder.getSurfaceFrame();
glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0);
+
+ mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ mEgl.eglDestroySurface(mEglDisplay, tmpSurface);
+
if(frame.width() > maxSize[0] || frame.height() > maxSize[0]) {
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEgl.eglTerminate(mEglDisplay);
@@ -639,9 +655,8 @@ public class ImageWallpaper extends WallpaperService {
maxSize[0] + "x" + maxSize[0]);
return false;
}
-
+
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
-
if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
int error = mEgl.eglGetError();
if (error == EGL_BAD_NATIVE_WINDOW || error == EGL_BAD_ALLOC) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index d0048bf440a9..14841af70f43 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1199,7 +1199,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurId = info.getId();
mCurToken = new Binder();
try {
- if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
+ if (true || DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
mIWindowManager.addWindowToken(mCurToken,
WindowManager.LayoutParams.TYPE_INPUT_METHOD);
} catch (RemoteException e) {
@@ -1237,14 +1237,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mMethodMap) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
+ IInputMethod prevMethod = mCurMethod;
mCurMethod = IInputMethod.Stub.asInterface(service);
if (mCurToken == null) {
Slog.w(TAG, "Service connected without a token!");
unbindCurrentMethodLocked(false, false);
return;
}
- // Remove commands relating to the previous service. Otherwise WindowManagerService
- // will reject the command because the token attached to these messages is invalid.
+ // Remove messages relating to the previous service. Otherwise WindowManagerService
+ // will throw a BadTokenException because the old token is being removed.
+ if (prevMethod != null) {
+ try {
+ prevMethod.removeSoftInputMessages();
+ } catch (RemoteException e) {
+ }
+ }
mCaller.removeMessages(MSG_SHOW_SOFT_INPUT);
mCaller.removeMessages(MSG_HIDE_SOFT_INPUT);
if (true || DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
@@ -2309,8 +2316,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
if (true || DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
+ msg.arg1 + ", " + args.arg2 + ")");
- ((IInputMethod)args.arg1).showSoftInput(msg.arg1,
- (ResultReceiver)args.arg2);
+ ((IInputMethod)args.arg1).showSoftInput(msg.arg1, (ResultReceiver)args.arg2);
} catch (RemoteException e) {
}
args.recycle();
@@ -2320,8 +2326,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
if (true || DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
+ args.arg2 + ")");
- ((IInputMethod)args.arg1).hideSoftInput(0,
- (ResultReceiver)args.arg2);
+ ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
} catch (RemoteException e) {
}
args.recycle();