diff options
| -rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 6 | ||||
| -rw-r--r-- | core/java/android/app/PendingIntent.java | 2 | ||||
| -rw-r--r-- | core/java/android/inputmethodservice/IInputMethodWrapper.java | 6 | ||||
| -rw-r--r-- | core/java/android/view/WindowManager.java | 18 | ||||
| -rw-r--r-- | core/java/com/android/internal/view/IInputMethod.aidl | 26 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 1 | ||||
| -rw-r--r-- | docs/html/index.jd | 5 | ||||
| -rw-r--r-- | packages/Shell/Android.mk | 2 | ||||
| -rw-r--r-- | packages/Shell/AndroidManifest.xml | 29 | ||||
| -rw-r--r-- | packages/Shell/res/layout/confirm_repeat.xml | 37 | ||||
| -rw-r--r-- | packages/Shell/res/values/strings.xml | 10 | ||||
| -rw-r--r-- | packages/Shell/res/xml/file_provider_paths.xml | 3 | ||||
| -rw-r--r-- | packages/Shell/src/com/android/shell/BugreportPrefs.java | 45 | ||||
| -rw-r--r-- | packages/Shell/src/com/android/shell/BugreportReceiver.java | 198 | ||||
| -rw-r--r-- | packages/Shell/src/com/android/shell/BugreportWarningActivity.java | 77 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/ImageWallpaper.java | 19 | ||||
| -rw-r--r-- | services/java/com/android/server/InputMethodManagerService.java | 19 |
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(); |