diff options
136 files changed, 1863 insertions, 813 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 193724d..d6db8c2 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4857,7 +4857,11 @@ public class Activity extends ContextThemeWrapper mFragments.dump(prefix, fd, writer, args); - getWindow().getDecorView().getViewRootImpl().dump(prefix, fd, writer, args); + if (getWindow() != null && + getWindow().peekDecorView() != null && + getWindow().peekDecorView().getViewRootImpl() != null) { + getWindow().peekDecorView().getViewRootImpl().dump(prefix, fd, writer, args); + } mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix); } diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 22a21cd..aab6ed8 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -205,7 +205,9 @@ public class KeyguardManager { try { mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() { public void onKeyguardExitResult(boolean success) throws RemoteException { - callback.onKeyguardExitResult(success); + if (callback != null) { + callback.onKeyguardExitResult(success); + } } }); } catch (RemoteException e) { diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 7bcf43e..2045ed8 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -58,10 +58,7 @@ public class StatusBarManager { | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK | DISABLE_SEARCH; - public static final int NAVIGATION_HINT_BACK_NOP = 1 << 0; - public static final int NAVIGATION_HINT_HOME_NOP = 1 << 1; - public static final int NAVIGATION_HINT_RECENT_NOP = 1 << 2; - public static final int NAVIGATION_HINT_BACK_ALT = 1 << 3; + public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0; public static final int WINDOW_STATUS_BAR = 1; public static final int WINDOW_NAVIGATION_BAR = 2; diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index 607930c..91b0d7c 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -146,7 +146,9 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { @Override public void shutdown() { synchronized (mLock) { - throwIfCalledByNotTrustedUidLocked(); + if (isConnectedLocked()) { + throwIfCalledByNotTrustedUidLocked(); + } throwIfShutdownLocked(); mIsShutdown = true; if (isConnectedLocked()) { diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index a9d0559..ddde3fb 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -398,135 +398,137 @@ public abstract class ContentProvider implements ComponentCallbacks2 { return AppOpsManager.MODE_ALLOWED; } - private void enforceReadPermissionInner(Uri uri) throws SecurityException { - final Context context = getContext(); - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - String missingPerm = null; - - if (UserHandle.isSameApp(uid, mMyUid)) { - return; + private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException { + enforceWritePermissionInner(uri); + if (mWriteOp != AppOpsManager.OP_NONE) { + return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg); } + return AppOpsManager.MODE_ALLOWED; + } + } - if (mExported) { - final String componentPerm = getReadPermission(); - if (componentPerm != null) { - if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) { - return; - } else { - missingPerm = componentPerm; - } + /** {@hide} */ + protected void enforceReadPermissionInner(Uri uri) throws SecurityException { + final Context context = getContext(); + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + String missingPerm = null; + + if (UserHandle.isSameApp(uid, mMyUid)) { + return; + } + + if (mExported) { + final String componentPerm = getReadPermission(); + if (componentPerm != null) { + if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) { + return; + } else { + missingPerm = componentPerm; } + } - // track if unprotected read is allowed; any denied - // <path-permission> below removes this ability - boolean allowDefaultRead = (componentPerm == null); - - final PathPermission[] pps = getPathPermissions(); - if (pps != null) { - final String path = uri.getPath(); - for (PathPermission pp : pps) { - final String pathPerm = pp.getReadPermission(); - if (pathPerm != null && pp.match(path)) { - if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) { - return; - } else { - // any denied <path-permission> means we lose - // default <provider> access. - allowDefaultRead = false; - missingPerm = pathPerm; - } + // track if unprotected read is allowed; any denied + // <path-permission> below removes this ability + boolean allowDefaultRead = (componentPerm == null); + + final PathPermission[] pps = getPathPermissions(); + if (pps != null) { + final String path = uri.getPath(); + for (PathPermission pp : pps) { + final String pathPerm = pp.getReadPermission(); + if (pathPerm != null && pp.match(path)) { + if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) { + return; + } else { + // any denied <path-permission> means we lose + // default <provider> access. + allowDefaultRead = false; + missingPerm = pathPerm; } } } - - // if we passed <path-permission> checks above, and no default - // <provider> permission, then allow access. - if (allowDefaultRead) return; - } - - // last chance, check against any uri grants - if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) - == PERMISSION_GRANTED) { - return; } - final String failReason = mExported - ? " requires " + missingPerm + ", or grantUriPermission()" - : " requires the provider be exported, or grantUriPermission()"; - throw new SecurityException("Permission Denial: reading " - + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid - + ", uid=" + uid + failReason); + // if we passed <path-permission> checks above, and no default + // <provider> permission, then allow access. + if (allowDefaultRead) return; } - private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException { - enforceWritePermissionInner(uri); - if (mWriteOp != AppOpsManager.OP_NONE) { - return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg); - } - return AppOpsManager.MODE_ALLOWED; + // last chance, check against any uri grants + if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) + == PERMISSION_GRANTED) { + return; } - private void enforceWritePermissionInner(Uri uri) throws SecurityException { - final Context context = getContext(); - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - String missingPerm = null; + final String failReason = mExported + ? " requires " + missingPerm + ", or grantUriPermission()" + : " requires the provider be exported, or grantUriPermission()"; + throw new SecurityException("Permission Denial: reading " + + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid + + ", uid=" + uid + failReason); + } - if (UserHandle.isSameApp(uid, mMyUid)) { - return; - } + /** {@hide} */ + protected void enforceWritePermissionInner(Uri uri) throws SecurityException { + final Context context = getContext(); + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + String missingPerm = null; - if (mExported) { - final String componentPerm = getWritePermission(); - if (componentPerm != null) { - if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) { - return; - } else { - missingPerm = componentPerm; - } + if (UserHandle.isSameApp(uid, mMyUid)) { + return; + } + + if (mExported) { + final String componentPerm = getWritePermission(); + if (componentPerm != null) { + if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) { + return; + } else { + missingPerm = componentPerm; } + } - // track if unprotected write is allowed; any denied - // <path-permission> below removes this ability - boolean allowDefaultWrite = (componentPerm == null); - - final PathPermission[] pps = getPathPermissions(); - if (pps != null) { - final String path = uri.getPath(); - for (PathPermission pp : pps) { - final String pathPerm = pp.getWritePermission(); - if (pathPerm != null && pp.match(path)) { - if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) { - return; - } else { - // any denied <path-permission> means we lose - // default <provider> access. - allowDefaultWrite = false; - missingPerm = pathPerm; - } + // track if unprotected write is allowed; any denied + // <path-permission> below removes this ability + boolean allowDefaultWrite = (componentPerm == null); + + final PathPermission[] pps = getPathPermissions(); + if (pps != null) { + final String path = uri.getPath(); + for (PathPermission pp : pps) { + final String pathPerm = pp.getWritePermission(); + if (pathPerm != null && pp.match(path)) { + if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) { + return; + } else { + // any denied <path-permission> means we lose + // default <provider> access. + allowDefaultWrite = false; + missingPerm = pathPerm; } } } - - // if we passed <path-permission> checks above, and no default - // <provider> permission, then allow access. - if (allowDefaultWrite) return; } - // last chance, check against any uri grants - if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - == PERMISSION_GRANTED) { - return; - } + // if we passed <path-permission> checks above, and no default + // <provider> permission, then allow access. + if (allowDefaultWrite) return; + } - final String failReason = mExported - ? " requires " + missingPerm + ", or grantUriPermission()" - : " requires the provider be exported, or grantUriPermission()"; - throw new SecurityException("Permission Denial: writing " - + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid - + ", uid=" + uid + failReason); + // last chance, check against any uri grants + if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + == PERMISSION_GRANTED) { + return; } + + final String failReason = mExported + ? " requires " + missingPerm + ", or grantUriPermission()" + : " requires the provider be exported, or grantUriPermission()"; + throw new SecurityException("Permission Denial: writing " + + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid + + ", uid=" + uid + failReason); } /** diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java index c5d0999..c428a17 100644 --- a/core/java/android/hardware/camera2/impl/CameraDevice.java +++ b/core/java/android/hardware/camera2/impl/CameraDevice.java @@ -19,27 +19,24 @@ package android.hardware.camera2.impl; import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE; import android.hardware.camera2.CameraAccessException; -import android.hardware.camera2.CameraMetadata; -import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.ICameraDeviceUser; import android.hardware.camera2.utils.CameraBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; -import android.os.IBinder; -import android.os.RemoteException; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; +import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import android.view.Surface; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; -import java.util.Stack; /** * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate @@ -49,6 +46,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { private final String TAG; private final boolean DEBUG; + private static final int REQUEST_ID_NONE = -1; + // TODO: guard every function with if (!mRemoteDevice) check (if it was closed) private ICameraDeviceUser mRemoteDevice; @@ -63,7 +62,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { private final SparseArray<CaptureListenerHolder> mCaptureListenerMap = new SparseArray<CaptureListenerHolder>(); - private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>(); + private int mRepeatingRequestId = REQUEST_ID_NONE; + private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>(); // Map stream IDs to Surfaces private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>(); @@ -186,7 +186,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { stopRepeating(); try { - mRemoteDevice.waitUntilIdle(); + waitUntilIdle(); // TODO: mRemoteDevice.beginConfigure // Delete all streams first (to free up HW resources) @@ -293,7 +293,11 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } if (repeating) { - mRepeatingRequestIdStack.add(requestId); + // Queue for deletion after in-flight requests finish + if (mRepeatingRequestId != REQUEST_ID_NONE) { + mRepeatingRequestIdDeletedList.add(mRepeatingRequestId); + } + mRepeatingRequestId = requestId; } if (mIdle) { @@ -327,8 +331,13 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { synchronized (mLock) { checkIfCameraClosed(); - while (!mRepeatingRequestIdStack.isEmpty()) { - int requestId = mRepeatingRequestIdStack.pop(); + if (mRepeatingRequestId != REQUEST_ID_NONE) { + + int requestId = mRepeatingRequestId; + mRepeatingRequestId = REQUEST_ID_NONE; + + // Queue for deletion after in-flight requests finish + mRepeatingRequestIdDeletedList.add(requestId); try { mRemoteDevice.cancelRequest(requestId); @@ -347,7 +356,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { synchronized (mLock) { checkIfCameraClosed(); - if (!mRepeatingRequestIdStack.isEmpty()) { + if (mRepeatingRequestId != REQUEST_ID_NONE) { throw new IllegalStateException("Active repeating request ongoing"); } @@ -359,6 +368,10 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { // impossible return; } + + mRepeatingRequestId = REQUEST_ID_NONE; + mRepeatingRequestIdDeletedList.clear(); + mCaptureListenerMap.clear(); } } @@ -572,13 +585,28 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { holder = CameraDevice.this.mCaptureListenerMap.get(requestId); // Clean up listener once we no longer expect to see it. - - // TODO: how to handle repeating listeners? - // we probably want cancelRequest to return # of times it already enqueued and - // keep a counter. if (holder != null && !holder.isRepeating()) { CameraDevice.this.mCaptureListenerMap.remove(requestId); } + + // TODO: add 'capture sequence completed' callback to the + // service, and clean up repeating requests there instead. + + // If we received a result for a repeating request and have + // prior repeating requests queued for deletion, remove those + // requests from mCaptureListenerMap. + if (holder != null && holder.isRepeating() + && mRepeatingRequestIdDeletedList.size() > 0) { + Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator(); + while (iter.hasNext()) { + int deletedRequestId = iter.next(); + if (deletedRequestId < requestId) { + CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId); + iter.remove(); + } + } + } + } // Check if we have a listener for this diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java index b674324..8a2c2b6 100644 --- a/core/java/android/net/PacProxySelector.java +++ b/core/java/android/net/PacProxySelector.java @@ -97,7 +97,7 @@ public class PacProxySelector extends ProxySelector { } catch (Exception e) { port = 8080; } - ret.add(new Proxy(Type.HTTP, new InetSocketAddress(host, port))); + ret.add(new Proxy(Type.HTTP, InetSocketAddress.createUnresolved(host, port))); } } if (ret.size() == 0) { diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index dbaa325..7ae8ca8 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -844,12 +844,13 @@ public abstract class BatteryStats implements Parcelable { public static final int DATA_CONNECTION_EVDO_B = 12; public static final int DATA_CONNECTION_LTE = 13; public static final int DATA_CONNECTION_EHRPD = 14; - public static final int DATA_CONNECTION_OTHER = 15; + public static final int DATA_CONNECTION_HSPAP = 15; + public static final int DATA_CONNECTION_OTHER = 16; static final String[] DATA_CONNECTION_NAMES = { "none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A", "1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte", - "ehrpd", "other" + "ehrpd", "hspap", "other" }; public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1; diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 2ab5a91..ed9264a 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -33,7 +33,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.Log; import android.util.TypedValue; import android.util.Xml; import android.view.LayoutInflater; @@ -125,8 +124,6 @@ public abstract class PreferenceActivity extends ListActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback { - private static final String TAG = "PreferenceActivity"; - // Constants for state save/restore private static final String HEADERS_TAG = ":android:headers"; private static final String CUR_HEADER_TAG = ":android:cur_header"; @@ -576,12 +573,14 @@ public abstract class PreferenceActivity extends ListActivity implements // Single pane, showing just a prefs fragment. findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE); mPrefsContainer.setVisibility(View.VISIBLE); + CharSequence initialTitleStr = null; + CharSequence initialShortTitleStr = null; if (initialTitle != 0) { - CharSequence initialTitleStr = getText(initialTitle); - CharSequence initialShortTitleStr = initialShortTitle != 0 + initialTitleStr = getText(initialTitle); + initialShortTitleStr = initialShortTitle != 0 ? getText(initialShortTitle) : null; - showBreadCrumbs(initialTitleStr, initialShortTitleStr); } + showBreadCrumbs(initialTitleStr, initialShortTitleStr); } else if (mHeaders.size() > 0) { setListAdapter(new HeaderAdapter(this, mHeaders)); if (!mSinglePane) { diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl index 9d384fb..2b95c12 100644 --- a/core/java/android/print/IPrintDocumentAdapter.aidl +++ b/core/java/android/print/IPrintDocumentAdapter.aidl @@ -37,4 +37,5 @@ oneway interface IPrintDocumentAdapter { void write(in PageRange[] pages, in ParcelFileDescriptor fd, IWriteResultCallback callback, int sequence); void finish(); + void cancel(); } diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index bbfc307..d6d56bb 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -616,6 +616,18 @@ public final class PrintManager { } @Override + public void cancel() { + // Start not called or finish called or destroyed - nothing to do. + if (!mStartReqeusted || mFinishRequested || mDestroyed) { + return; + } + // Request cancellation of pending work if needed. + synchronized (mLock) { + cancelPreviousCancellableOperationLocked(); + } + } + + @Override public void onActivityPaused(Activity activity) { /* do nothing */ } diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index e35b8eb..cc81be5 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -216,6 +216,8 @@ public abstract class DocumentsProvider extends ContentProvider { * {@link Root#FLAG_SUPPORTS_RECENTS}. The returned documents should be * sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and * limited to only return the 64 most recently modified documents. + * <p> + * Recent documents do not support change notifications. * * @param projection list of {@link Document} columns to put into the * cursor. If {@code null} all supported columns should be @@ -512,10 +514,7 @@ public abstract class DocumentsProvider extends ContentProvider { final boolean callerHasManage = context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS) == PackageManager.PERMISSION_GRANTED; - if (!callerHasManage) { - getContext().enforceCallingOrSelfUriPermission( - documentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, method); - } + enforceWritePermissionInner(documentUri); final Bundle out = new Bundle(); try { diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index b808363..2752085 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -993,8 +993,16 @@ public class TextToSpeech { return runAction(new Action<Set<String>>() { @Override public Set<String> run(ITextToSpeechService service) throws RemoteException { - String[] features = service.getFeaturesForLanguage( + String[] features = null; + try { + features = service.getFeaturesForLanguage( locale.getISO3Language(), locale.getISO3Country(), locale.getVariant()); + } catch(MissingResourceException e) { + Log.w(TAG, "Couldn't retrieve 3 letter ISO 639-2/T language and/or ISO 3166 " + + "country code for locale: " + locale, e); + return null; + } + if (features != null) { final Set<String> featureSet = new HashSet<String>(); Collections.addAll(featureSet, features); diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java index 5fbd22e..4f996cd 100644 --- a/core/java/android/speech/tts/TtsEngines.java +++ b/core/java/android/speech/tts/TtsEngines.java @@ -44,6 +44,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; +import java.util.MissingResourceException; /** * Support class for querying the list of available engines @@ -369,28 +370,34 @@ public class TtsEngines { public String getDefaultLocale() { final Locale locale = Locale.getDefault(); - // Note that the default locale might have an empty variant - // or language, and we take care that the construction is - // the same as {@link #getV1Locale} i.e no trailing delimiters - // or spaces. - String defaultLocale = locale.getISO3Language(); - if (TextUtils.isEmpty(defaultLocale)) { - Log.w(TAG, "Default locale is empty."); - return ""; - } + try { + // Note that the default locale might have an empty variant + // or language, and we take care that the construction is + // the same as {@link #getV1Locale} i.e no trailing delimiters + // or spaces. + String defaultLocale = locale.getISO3Language(); + if (TextUtils.isEmpty(defaultLocale)) { + Log.w(TAG, "Default locale is empty."); + return ""; + } + + if (!TextUtils.isEmpty(locale.getISO3Country())) { + defaultLocale += LOCALE_DELIMITER + locale.getISO3Country(); + } else { + // Do not allow locales of the form lang--variant with + // an empty country. + return defaultLocale; + } + if (!TextUtils.isEmpty(locale.getVariant())) { + defaultLocale += LOCALE_DELIMITER + locale.getVariant(); + } - if (!TextUtils.isEmpty(locale.getISO3Country())) { - defaultLocale += LOCALE_DELIMITER + locale.getISO3Country(); - } else { - // Do not allow locales of the form lang--variant with - // an empty country. return defaultLocale; + } catch (MissingResourceException e) { + // Default locale does not have a ISO 3166 and/or ISO 639-2/T codes. Return the + // default "eng-usa" (that would be the result of Locale.getDefault() == Locale.US). + return "eng-usa"; } - if (!TextUtils.isEmpty(locale.getVariant())) { - defaultLocale += LOCALE_DELIMITER + locale.getVariant(); - } - - return defaultLocale; } /** diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index 160c630..f839d52 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -391,6 +391,15 @@ public class Html { out.append(">"); } else if (c == '&') { out.append("&"); + } else if (c >= 0xD800 && c <= 0xDFFF) { + if (c < 0xDC00 && i + 1 < end) { + char d = text.charAt(i + 1); + if (d >= 0xDC00 && d <= 0xDFFF) { + i++; + int codepoint = 0x010000 | (int) c - 0xD800 << 10 | (int) d - 0xDC00; + out.append("&#").append(codepoint).append(";"); + } + } } else if (c > 0x7E || c < ' ') { out.append("&#").append((int) c).append(";"); } else if (c == ' ') { diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index f76e190..da9ba5a 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -1255,7 +1255,8 @@ public abstract class Transition implements Cloneable { Animator anim = runningAnimators.keyAt(i); if (anim != null) { AnimationInfo oldInfo = runningAnimators.get(anim); - if (oldInfo != null) { + if (oldInfo != null && oldInfo.view != null && + oldInfo.view.getContext() == sceneRoot.getContext()) { boolean cancel = false; TransitionValues oldValues = oldInfo.values; View oldView = oldInfo.view; diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java index 4af0f51..9f77d5e 100644 --- a/core/java/android/transition/TransitionInflater.java +++ b/core/java/android/transition/TransitionInflater.java @@ -20,9 +20,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.util.ArrayMap; import android.util.AttributeSet; -import android.util.SparseArray; import android.util.Xml; import android.view.InflateException; import android.view.ViewGroup; @@ -43,15 +41,7 @@ import java.util.ArrayList; */ public class TransitionInflater { - // We only need one inflater for any given context. Also, this allows us to associate - // ids with unique instances per-Context, used to avoid re-inflating - // already-inflated resources into new/different instances - private static final ArrayMap<Context, TransitionInflater> sInflaterMap = - new ArrayMap<Context, TransitionInflater>(); - private Context mContext; - // TODO: do we need id maps for transitions and transitionMgrs as well? - SparseArray<Scene> mScenes = new SparseArray<Scene>(); private TransitionInflater(Context context) { mContext = context; @@ -61,13 +51,7 @@ public class TransitionInflater { * Obtains the TransitionInflater from the given context. */ public static TransitionInflater from(Context context) { - TransitionInflater inflater = sInflaterMap.get(context); - if (inflater != null) { - return inflater; - } - inflater = new TransitionInflater(context); - sInflaterMap.put(context, inflater); - return inflater; + return new TransitionInflater(context); } /** diff --git a/core/java/android/util/MapCollections.java b/core/java/android/util/MapCollections.java index f4a9b0b..28b788b 100644 --- a/core/java/android/util/MapCollections.java +++ b/core/java/android/util/MapCollections.java @@ -97,10 +97,10 @@ abstract class MapCollections<K, V> { if (!mEntryValid) { throw new IllegalStateException(); } + colRemoveAt(mIndex); mIndex--; mEnd--; mEntryValid = false; - colRemoveAt(mIndex); } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6c04c0b..b74202d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3102,6 +3102,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; + private boolean mUseBackgroundPadding = false; + /** * @hide */ @@ -5900,6 +5902,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sThreadLocal.set(localInsets); } boolean res = computeFitSystemWindows(insets, localInsets); + mUserPaddingLeftInitial = localInsets.left; + mUserPaddingRightInitial = localInsets.right; internalSetPadding(localInsets.left, localInsets.top, localInsets.right, localInsets.bottom); return res; @@ -12133,12 +12137,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!isTextAlignmentResolved()) { resolveTextAlignment(); } - if (!isPaddingResolved()) { - resolvePadding(); - } + // Should resolve Drawables before Padding because we need the layout direction of the + // Drawable to correctly resolve Padding. if (!isDrawablesResolved()) { resolveDrawables(); } + if (!isPaddingResolved()) { + resolvePadding(); + } onRtlPropertiesChanged(getLayoutDirection()); return true; } @@ -12341,6 +12347,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // If start / end padding are defined, they will be resolved (hence overriding) to // left / right or right / left depending on the resolved layout direction. // If start / end padding are not defined, use the left / right ones. + if (mBackground != null && mUseBackgroundPadding) { + Rect padding = sThreadLocal.get(); + if (padding == null) { + padding = new Rect(); + sThreadLocal.set(padding); + } + mBackground.getPadding(padding); + mUserPaddingLeftInitial = padding.left; + mUserPaddingRightInitial = padding.right; + } switch (resolvedLayoutDirection) { case LAYOUT_DIRECTION_RTL: if (mUserPaddingStart != UNDEFINED_PADDING) { @@ -15336,6 +15352,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mUserPaddingRightInitial = padding.right; internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); } + mUseBackgroundPadding = true; + } else { + mUseBackgroundPadding = false; } // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or @@ -15361,6 +15380,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /* Remove the background */ mBackground = null; + mUseBackgroundPadding = false; + if ((mPrivateFlags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0) { /* * This view ONLY drew the background before and we're removing @@ -15432,6 +15453,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mUserPaddingLeftInitial = left; mUserPaddingRightInitial = right; + mUseBackgroundPadding = false; + internalSetPadding(left, top, right, bottom); } @@ -15518,6 +15541,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mUserPaddingStart = start; mUserPaddingEnd = end; + mUseBackgroundPadding = false; + switch(getLayoutDirection()) { case LAYOUT_DIRECTION_RTL: mUserPaddingLeftInitial = end; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 637af6f..bc0d7e3 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3393,16 +3393,7 @@ public final class ViewRootImpl implements ViewParent, public final void deliver(QueuedInputEvent q) { if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { forward(q); - } else if (mView == null || !mAdded) { - Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent); - finish(q, false); - } else if (!mAttachInfo.mHasWindowFocus && - !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) && - !isTerminalInputEvent(q.mEvent)) { - // If this is a focused event and the window doesn't currently have input focus, - // then drop this event. This could be an event that came back from the previous - // stage but the window has lost focus in the meantime. - Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent); + } else if (shouldDropInputEvent(q)) { finish(q, false); } else { apply(q, onProcess(q)); @@ -3461,6 +3452,22 @@ public final class ViewRootImpl implements ViewParent, } } + protected boolean shouldDropInputEvent(QueuedInputEvent q) { + if (mView == null || !mAdded) { + Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent); + return true; + } else if (!mAttachInfo.mHasWindowFocus && + !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) && + !isTerminalInputEvent(q.mEvent)) { + // If this is a focused event and the window doesn't currently have input focus, + // then drop this event. This could be an event that came back from the previous + // stage but the window has lost focus in the meantime. + Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent); + return true; + } + return false; + } + void dump(String prefix, PrintWriter writer) { if (mNext != null) { mNext.dump(prefix, writer); @@ -3846,6 +3853,10 @@ public final class ViewRootImpl implements ViewParent, return FINISH_HANDLED; } + if (shouldDropInputEvent(q)) { + return FINISH_NOT_HANDLED; + } + // If the Control modifier is held, try to interpret the key as a shortcut. if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed() @@ -3854,12 +3865,18 @@ public final class ViewRootImpl implements ViewParent, if (mView.dispatchKeyShortcutEvent(event)) { return FINISH_HANDLED; } + if (shouldDropInputEvent(q)) { + return FINISH_NOT_HANDLED; + } } // Apply the fallback event policy. if (mFallbackEventHandler.dispatchKeyEvent(event)) { return FINISH_HANDLED; } + if (shouldDropInputEvent(q)) { + return FINISH_NOT_HANDLED; + } // Handle automatic focus changes. if (event.getAction() == KeyEvent.ACTION_DOWN) { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3eb0052..092f474 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -6686,6 +6686,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te scrap.dispatchStartTemporaryDetach(); + // The the accessibility state of the view may change while temporary + // detached and we do not allow detached views to fire accessibility + // events. So we are announcing that the subtree changed giving a chance + // to clients holding on to a view in this subtree to refresh it. + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); + // Don't scrap views that have transient state. final boolean scrapHasTransientState = scrap.hasTransientState(); if (scrapHasTransientState) { diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 65a2d4d..5392a96 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -959,9 +959,11 @@ public class ProgressBar extends View { if (!mInDrawing) { if (verifyDrawable(dr)) { final Rect dirty = dr.getBounds(); + final int scrollX = mScrollX + mPaddingLeft; + final int scrollY = mScrollY + mPaddingTop; - invalidate(dirty.left + mScrollX, dirty.top + mScrollY, - dirty.right + mScrollX, dirty.bottom + mScrollY); + invalidate(dirty.left + scrollX, dirty.top + scrollY, + dirty.right + scrollX, dirty.bottom + scrollY); } else { super.invalidateDrawable(dr); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index cb930d6..7a9809f 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -56,6 +56,7 @@ import android.text.Selection; import android.text.SpanWatcher; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.SpannedString; import android.text.StaticLayout; @@ -3494,19 +3495,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ss.selEnd = end; if (mText instanceof Spanned) { - /* - * Calling setText() strips off any ChangeWatchers; - * strip them now to avoid leaking references. - * But do it to a copy so that if there are any - * further changes to the text of this view, it - * won't get into an inconsistent state. - */ - - Spannable sp = new SpannableString(mText); - - for (ChangeWatcher cw : sp.getSpans(0, sp.length(), ChangeWatcher.class)) { - sp.removeSpan(cw); - } + Spannable sp = new SpannableStringBuilder(mText); if (mEditor != null) { removeMisspelledSpans(sp); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index e0a154c..a99aa33 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -2172,6 +2172,9 @@ public final class BatteryStatsImpl extends BatteryStats { case TelephonyManager.NETWORK_TYPE_EHRPD: bin = DATA_CONNECTION_EHRPD; break; + case TelephonyManager.NETWORK_TYPE_HSPAP: + bin = DATA_CONNECTION_HSPAP; + break; default: bin = DATA_CONNECTION_OTHER; break; diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 73d34c3..c44afae 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -301,6 +301,8 @@ public class ZygoteInit { count++; } catch (ClassNotFoundException e) { Log.w(TAG, "Class not found for preloading: " + line); + } catch (UnsatisfiedLinkError e) { + Log.w(TAG, "Problem preloading " + line + ": " + e); } catch (Throwable t) { Log.e(TAG, "Error preloading " + line + ".", t); if (t instanceof Error) { diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index 44e7ec1..4654178 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -721,7 +721,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter if (subMenu == null) return false; mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); - return false; + final MenuPresenter.Callback cb = getCallback(); + return cb != null ? cb.onOpenSubMenu(subMenu) : false; } @Override @@ -729,6 +730,10 @@ public class ActionMenuPresenter extends BaseMenuPresenter if (menu instanceof SubMenuBuilder) { ((SubMenuBuilder) menu).getRootMenu().close(false); } + final MenuPresenter.Callback cb = getCallback(); + if (cb != null) { + cb.onCloseMenu(menu, allMenusAreClosing); + } } } diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java index db0d6dd..92e9ea6 100644 --- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java @@ -144,6 +144,10 @@ public abstract class BaseMenuPresenter implements MenuPresenter { mCallback = cb; } + public Callback getCallback() { + return mCallback; + } + /** * Create a new item view that can be re-bound to other item data later. * diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index b5d74e8..5f9d8f2 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -566,7 +566,11 @@ public class ActionBarView extends AbsActionBarView { mUpGoerFive.setEnabled(enable); mUpGoerFive.setFocusable(enable); // Make sure the home button has an accurate content description for accessibility. - if (!enable) { + updateHomeAccessibility(enable); + } + + private void updateHomeAccessibility(boolean homeEnabled) { + if (!homeEnabled) { mUpGoerFive.setContentDescription(null); mUpGoerFive.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); } else { @@ -677,19 +681,7 @@ public class ActionBarView extends AbsActionBarView { } // Make sure the home button has an accurate content description for accessibility. - if (!mHomeLayout.isEnabled()) { - mHomeLayout.setContentDescription(null); - mHomeLayout.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - } else { - mHomeLayout.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_AUTO); - if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) { - mHomeLayout.setContentDescription(mContext.getResources().getText( - R.string.action_bar_up_description)); - } else { - mHomeLayout.setContentDescription(mContext.getResources().getText( - R.string.action_bar_home_description)); - } - } + updateHomeAccessibility(!mUpGoerFive.isEnabled()); } public void setIcon(Drawable icon) { diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index a7a0bb2..ccd75d5 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -34,6 +34,13 @@ static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name, if (NULL != name) { AutoJavaStringToUTF8 str(env, name); face = SkTypeface::CreateFromName(str.c_str(), style); + // Try to find the closest matching font, using the standard heuristic + if (NULL == face) { + face = SkTypeface::CreateFromName(str.c_str(), (SkTypeface::Style)(style ^ SkTypeface::kItalic)); + } + for (int i = 0; NULL == face && i < 4; i++) { + face = SkTypeface::CreateFromName(str.c_str(), (SkTypeface::Style)i); + } } // return the default font at the best style if no exact match exists @@ -45,8 +52,13 @@ static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name, static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* family, int style) { SkTypeface* face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style); - // return the default font at the best style if the requested style does not - // exist in the provided family + // Try to find the closest matching font, using the standard heuristic + if (NULL == face) { + face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic)); + } + for (int i = 0; NULL == face && i < 4; i++) { + face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)i); + } if (NULL == face) { face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style); } diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png Binary files differindex ca65994..a804a8a 100644 --- a/core/res/res/drawable-hdpi/toast_frame.9.png +++ b/core/res/res/drawable-hdpi/toast_frame.9.png diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png Binary files differdeleted file mode 100644 index a804a8a..0000000 --- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/toast_frame.9.png b/core/res/res/drawable-ldpi/toast_frame.9.png Binary files differindex 3b344ff..e64dc75 100644 --- a/core/res/res/drawable-ldpi/toast_frame.9.png +++ b/core/res/res/drawable-ldpi/toast_frame.9.png diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png Binary files differindex 9e93fe7..778e4e6 100644 --- a/core/res/res/drawable-mdpi/toast_frame.9.png +++ b/core/res/res/drawable-mdpi/toast_frame.9.png diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png Binary files differdeleted file mode 100644 index 778e4e6..0000000 --- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png Binary files differindex 1f63420..77e69c7 100644 --- a/core/res/res/drawable-xhdpi/toast_frame.9.png +++ b/core/res/res/drawable-xhdpi/toast_frame.9.png diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png Binary files differdeleted file mode 100644 index 77e69c7..0000000 --- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/toast_frame.9.png b/core/res/res/drawable-xxhdpi/toast_frame.9.png Binary files differindex 882b9c6..edecb63 100644 --- a/core/res/res/drawable-xxhdpi/toast_frame.9.png +++ b/core/res/res/drawable-xxhdpi/toast_frame.9.png diff --git a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png Binary files differdeleted file mode 100644 index edecb63..0000000 --- a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png +++ /dev/null diff --git a/core/res/res/values-mcc311-mnc190/config.xml b/core/res/res/values-mcc311-mnc190/config.xml new file mode 100644 index 0000000..a6c4d1b --- /dev/null +++ b/core/res/res/values-mcc311-mnc190/config.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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 my 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. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering --> + <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or + <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH --> + <integer-array translatable="false" name="config_tether_upstream_types"> + <item>1</item> + <item>4</item> + <item>7</item> + <item>9</item> + </integer-array> + + <!-- String containing the apn value for tethering. May be overriden by secure settings + TETHER_DUN_APN. Value is a comma separated series of strings: + "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type" + note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> + <string translatable="false" name="config_tether_apndata">Tether,broadband.cellular1.net,,,,,,,,,311,190,,DUN</string> + +</resources> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index ef30b98..91af50a 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -22,7 +22,7 @@ <!-- Do not translate. These are all of the drawable resources that should be preloaded by the zygote process before it starts forking application processes. --> <array name="preloaded_drawables"> - <item>@drawable/toast_frame_holo</item> + <item>@drawable/toast_frame</item> <item>@drawable/btn_check_on_pressed_holo_light</item> <item>@drawable/btn_check_on_pressed_holo_dark</item> <item>@drawable/btn_check_on_holo_light</item> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 42ea384..18cf57d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -585,8 +585,8 @@ <!-- Disable lockscreen rotation by default --> <bool name="config_enableLockScreenRotation">false</bool> - <!-- Disable lockscreen translucent decor by default --> - <bool name="config_enableLockScreenTranslucentDecor">false</bool> + <!-- Enable lockscreen translucent decor by default --> + <bool name="config_enableLockScreenTranslucentDecor">true</bool> <!-- Enable translucent decor by default --> <bool name="config_enableTranslucentDecor">true</bool> @@ -1176,6 +1176,19 @@ where if the preferred is used we don't try the others. --> <bool name="config_dontPreferApn">false</bool> + <!-- The list of ril radio technologies (see ServiceState.java) which only support + a single data connection at one time. This may change by carrier via + overlays (some don't support multiple pdp on UMTS). All unlisted radio + tech types support unlimited types (practically only 2-4 used). --> + <integer-array name="config_onlySingleDcAllowed"> + <item>4</item> <!-- IS95A --> + <item>5</item> <!-- IS95B --> + <item>6</item> <!-- 1xRTT --> + <item>7</item> <!-- EVDO_0 --> + <item>8</item> <!-- EVDO_A --> + <item>12</item> <!-- EVDO_B --> + </integer-array> + <!-- Vibrator pattern to be used as the default for notifications that specify DEFAULT_VIBRATE. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 22a9402..b85bff4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1435,6 +1435,7 @@ <java-symbol type="array" name="config_locationProviderPackageNames" /> <java-symbol type="array" name="config_defaultNotificationVibePattern" /> <java-symbol type="array" name="config_notificationFallbackVibePattern" /> + <java-symbol type="array" name="config_onlySingleDcAllowed" /> <java-symbol type="bool" name="config_animateScreenLights" /> <java-symbol type="bool" name="config_automatic_brightness_available" /> <java-symbol type="bool" name="config_enableFusedLocationOverlay" /> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 4c80e7d..c8d9fc6 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -1048,7 +1048,7 @@ please see themes_device_defaults.xml. <item name="presentationTheme">@android:style/Theme.Holo.Dialog.Presentation</item> <!-- Toast attributes --> - <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item> + <item name="toastFrameBackground">@android:drawable/toast_frame</item> <!-- Panel attributes --> <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_dark</item> @@ -1363,7 +1363,7 @@ please see themes_device_defaults.xml. <item name="presentationTheme">@android:style/Theme.Holo.Light.Dialog.Presentation</item> <!-- Toast attributes --> - <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item> + <item name="toastFrameBackground">@android:drawable/toast_frame</item> <!-- Panel attributes --> <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_light</item> diff --git a/data/keyboards/AVRCP.kl b/data/keyboards/AVRCP.kl index 736b43c..4c91ece 100644 --- a/data/keyboards/AVRCP.kl +++ b/data/keyboards/AVRCP.kl @@ -14,8 +14,8 @@ # Key layout used for Bluetooth AVRCP support. -key 200 MEDIA_PLAY WAKE -key 201 MEDIA_PAUSE WAKE +key 200 MEDIA_PLAY_PAUSE WAKE +key 201 MEDIA_PLAY_PAUSE WAKE key 166 MEDIA_STOP WAKE key 163 MEDIA_NEXT WAKE key 165 MEDIA_PREVIOUS WAKE diff --git a/docs/html/about/versions/kitkat.jd b/docs/html/about/versions/kitkat.jd index 6c6cb6c..92ebf65 100644 --- a/docs/html/about/versions/kitkat.jd +++ b/docs/html/about/versions/kitkat.jd @@ -55,7 +55,7 @@ window.onhashchange = function () { <div id="44-android-44" class="version-section"> <div style="padding:0px 0px 0px 60px;margin-top:-3px;float:right;"> - <img src="{@docRoot}images/kk-android-44.png" alt="Android 4.4 on phone and tablet" width="380"> + <img src="{@docRoot}design/media/index_landing_page.png" alt="Android 4.4 on phone and tablet" width="380"> </div> <div class="landing-docs" style="float:right;clear:both;margin:22px 0 2em 3em;"> @@ -143,7 +143,8 @@ window.onhashchange = function () { lets you tune your app's behavior to match the device's memory configuration. You can modify or disable large-memory features as needed, depending on the use-cases you want to support on entry-level devices. Learn more about - optimizing your apps for low-memory devices <a href="">here</a>. + optimizing your apps for low-memory devices <a + href="{@docRoot}training/articles/memory.html">here</a>. </p> <p> @@ -612,18 +613,20 @@ window.onhashchange = function () { Now it's easy to create high-quality video of your app, directly from your Android device. <span style="white-space:nowrap;">Android 4.4</span> adds support for screen recording and provides a <strong>screen recording - utility</strong> that lets you capture video as you use the device and store - it as an MP4 file. It's a great new way to create walkthroughs and tutorials - for your app, testing materials, marketing videos, and much more. + utility</strong> that lets you start and stop recording on a device that's + connected to your Android SDK environment over USB. It's a great new way to + create walkthroughs and tutorials for your app, testing materials, marketing + videos, and more. </p> <p> - You can record at any device-supported resolution and bitrate you want, and - the output retains the aspect ratio of the display. By default, the utility - selects a resolution equal or close to the device's display resolution in the - current orientation. When you are done recording, you can share the video - directly from your device or pull the MP4 file to your host computer for - post-production. + With the screen recording utility, you can capture video of your device screen + contents and store the video as an MP4 file on the device. You can record at any + device-supported resolution and bitrate you want, and the output retains the + aspect ratio of the display. By default, the utility selects a resolution + equal or close to the device's display resolution in the current orientation. + When you are done recording, you can share the video directly from your + device or pull the MP4 file to your host computer for post-production. </p> <p> @@ -827,9 +830,7 @@ window.onhashchange = function () { <p> <span style="white-space:nowrap;">Android 4.4</span> upgrades its - SurfaceFlinger from OpenGL ES 1.0 to OpenGL ES 2.0. This boosts performance - by using multi-texturing, and it improves color calibration and supports more - advanced special effects. + SurfaceFlinger from OpenGL ES 1.0 to OpenGL ES 2.0. </p> <h4 id="44-composer">New Hardware Composer support for virtual displays</h4> diff --git a/docs/html/images/kk-saf2-n5.jpg b/docs/html/images/kk-saf2-n5.jpg Binary files differindex c96d5d4..1c54a95 100644 --- a/docs/html/images/kk-saf2-n5.jpg +++ b/docs/html/images/kk-saf2-n5.jpg diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 6d60dd2..3c24683 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1167,6 +1167,11 @@ public final class Bitmap implements Parcelable { * @see #reconfigure(int, int, Config) */ public final int getAllocationByteCount() { + if (mBuffer == null) { + // native backed bitmaps don't support reconfiguration, + // so alloc size is always content size + return getByteCount(); + } return mBuffer.length; } diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 6fd1763..429be49 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -259,14 +259,26 @@ public class BitmapFactory { * (e.g. the bitmap is drawn, getPixels() is called), they will be * automatically re-decoded. * - * For the re-decode to happen, the bitmap must have access to the + * <p>For the re-decode to happen, the bitmap must have access to the * encoded data, either by sharing a reference to the input * or by making a copy of it. This distinction is controlled by * inInputShareable. If this is true, then the bitmap may keep a shallow * reference to the input. If this is false, then the bitmap will * explicitly make a copy of the input data, and keep that. Even if * sharing is allowed, the implementation may still decide to make a - * deep copy of the input data. + * deep copy of the input data.</p> + * + * <p>While inPurgeable can help avoid big Dalvik heap allocations (from + * API level 11 onward), it sacrifices performance predictability since any + * image that the view system tries to draw may incur a decode delay which + * can lead to dropped frames. Therefore, most apps should avoid using + * inPurgeable to allow for a fast and fluid UI. To minimize Dalvik heap + * allocations use the {@link #inBitmap} flag instead.</p> + * + * <p class="note"><strong>Note:</strong> This flag is ignored when used + * with {@link #decodeResource(Resources, int, + * android.graphics.BitmapFactory.Options)} or {@link #decodeFile(String, + * android.graphics.BitmapFactory.Options)}.</p> */ public boolean inPurgeable; diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index e350e8d..af8441a 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -23,6 +23,7 @@ import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.SystemClock; +import android.util.LayoutDirection; import android.util.SparseArray; /** @@ -59,6 +60,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { private long mExitAnimationEnd; private Drawable mLastDrawable; + private Insets mInsets = Insets.NONE; + // overrides from Drawable @Override @@ -78,18 +81,30 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { | mDrawableContainerState.mChildrenChangingConfigurations; } + private boolean needsMirroring() { + return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL; + } + @Override public boolean getPadding(Rect padding) { final Rect r = mDrawableContainerState.getConstantPadding(); + boolean result = true; if (r != null) { padding.set(r); - return true; - } - if (mCurrDrawable != null) { - return mCurrDrawable.getPadding(padding); } else { - return super.getPadding(padding); + if (mCurrDrawable != null) { + result = mCurrDrawable.getPadding(padding); + } else { + result = super.getPadding(padding); + } } + if (needsMirroring()) { + final int left = padding.left; + final int right = padding.right; + padding.left = right; + padding.right = left; + } + return result; } /** @@ -97,7 +112,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { */ @Override public Insets getOpticalInsets() { - return (mCurrDrawable == null) ? Insets.NONE : mCurrDrawable.getOpticalInsets(); + return mInsets; } @Override @@ -334,6 +349,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mCurrDrawable = d; mCurIndex = idx; if (d != null) { + mInsets = d.getOpticalInsets(); d.mutate(); if (mDrawableContainerState.mEnterFadeDuration > 0) { mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration; @@ -348,9 +364,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { d.setBounds(getBounds()); d.setLayoutDirection(getLayoutDirection()); d.setAutoMirrored(mDrawableContainerState.mAutoMirrored); + } else { + mInsets = Insets.NONE; } } else { mCurrDrawable = null; + mInsets = Insets.NONE; mCurIndex = -1; } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 1f5fefd..b836f50 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -2913,12 +2913,10 @@ public class AudioService extends IAudioService.Stub { int index; if (isMuted()) { index = 0; - } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC && - (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && + } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) { index = (mIndexMax + 5)/10; - } - else { + } else { index = (getIndex(device) + 5)/10; } AudioSystem.setStreamVolumeIndex(mStreamType, index, device); @@ -2943,6 +2941,9 @@ public class AudioService extends IAudioService.Stub { if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (isMuted()) { index = 0; + } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && + mAvrcpAbsVolSupported) { + index = (mIndexMax + 5)/10; } else { index = ((Integer)entry.getValue() + 5)/10; } @@ -3215,7 +3216,14 @@ public class AudioService extends IAudioService.Stub { for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (streamType != streamState.mStreamType && mStreamVolumeAlias[streamType] == streamState.mStreamType) { - mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); + // Make sure volume is also maxed out on A2DP device for aliased stream + // that may have a different device selected + int streamDevice = getDeviceForStream(streamType); + if ((device != streamDevice) && mAvrcpAbsVolSupported && + ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) { + mStreamStates[streamType].applyDeviceVolume(device); + } + mStreamStates[streamType].applyDeviceVolume(streamDevice); } } @@ -3843,9 +3851,12 @@ public class AudioService extends IAudioService.Stub { // address is not used for now, but may be used when multiple a2dp devices are supported synchronized (mA2dpAvrcpLock) { mAvrcpAbsVolSupported = support; - VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC]; sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE, - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0); + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, + mStreamStates[AudioSystem.STREAM_MUSIC], 0); + sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE, + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, + mStreamStates[AudioSystem.STREAM_RING], 0); } } diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml index 8be15cb..b4847f0 100644 --- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml +++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml @@ -32,12 +32,10 @@ android:id="@+id/carrier_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:singleLine="true" android:ellipsize="marquee" android:textAppearance="?android:attr/textAppearanceMedium" android:textSize="@dimen/kg_status_line_font_size" - android:textColor="?android:attr/textColorSecondary" - android:textAllCaps="@bool/kg_use_all_caps" /> + android:textColor="?android:attr/textColorSecondary" /> <LinearLayout android:layout_width="match_parent" diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java index 7d1f24f..3dc4d5c 100644 --- a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java +++ b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java @@ -243,11 +243,12 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0; final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0; - mPreview.setPivotX(0); + final boolean isRtl = mPreview.getLayoutDirection() == LAYOUT_DIRECTION_RTL; + mPreview.setPivotX(isRtl ? mPreview.width : 0); mPreview.setPivotY(0); mPreview.setScaleX(pvScale); mPreview.setScaleY(pvScale); - mPreview.setTranslationX(pvTransX); + mPreview.setTranslationX((isRtl ? -1 : 1) * pvTransX); mPreview.setTranslationY(pvTransY); mRenderedSize.set(width, height); diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java index c33f174..88558cd 100644 --- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java +++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java @@ -17,14 +17,18 @@ package com.android.keyguard; import android.content.Context; +import android.text.method.SingleLineTransformationMethod; import android.text.TextUtils; import android.util.AttributeSet; +import android.view.View; import android.widget.TextView; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.widget.LockPatternUtils; +import java.util.Locale; + public class CarrierText extends TextView { private static CharSequence mSeparator; @@ -77,6 +81,8 @@ public class CarrierText extends TextView { public CarrierText(Context context, AttributeSet attrs) { super(context, attrs); mLockPatternUtils = new LockPatternUtils(mContext); + boolean useAllCaps = mContext.getResources().getBoolean(R.bool.kg_use_all_caps); + setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps)); } protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) { @@ -258,4 +264,25 @@ public class CarrierText extends TextView { return mContext.getText(carrierHelpTextId); } + + private class CarrierTextTransformationMethod extends SingleLineTransformationMethod { + private final Locale mLocale; + private final boolean mAllCaps; + + public CarrierTextTransformationMethod(Context context, boolean allCaps) { + mLocale = context.getResources().getConfiguration().locale; + mAllCaps = allCaps; + } + + @Override + public CharSequence getTransformation(CharSequence source, View view) { + source = super.getTransformation(source, view); + + if (mAllCaps && source != null) { + source = source.toString().toUpperCase(mLocale); + } + + return source; + } + } } diff --git a/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java index 677f1f1..2ee21ac 100644 --- a/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java +++ b/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java @@ -39,7 +39,7 @@ public interface ChallengeLayout { * * @param b true to show, false to hide */ - void showChallenge(boolean b); + void showChallenge(boolean show); /** * Show the bouncer challenge. This may block access to other child views. diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java index 9a1aa5b..0a915ea 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java @@ -99,6 +99,11 @@ public abstract class KeyguardActivityLauncher { public void launchCamera(Handler worker, Runnable onSecureCameraStarted) { LockPatternUtils lockPatternUtils = getLockPatternUtils(); + + // Workaround to avoid camera release/acquisition race when resuming face unlock + // after showing lockscreen camera (bug 11063890). + KeyguardUpdateMonitor.getInstance(getContext()).setAlternateUnlockEnabled(false); + if (lockPatternUtils.isSecure()) { // Launch the secure version of the camera if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java index fdc06a6..1bae9b8 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java @@ -218,7 +218,7 @@ public class KeyguardHostView extends KeyguardViewBase { mTransportState = (dcs.clearing ? TRANSPORT_GONE : (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE)); - if (DEBUG) Log.v(TAG, "Initial transport state: " + if (DEBUGXPORT) Log.v(TAG, "Initial transport state: " + mTransportState + ", pbstate=" + dcs.playbackState); } @@ -1369,7 +1369,7 @@ public class KeyguardHostView extends KeyguardViewBase { } } - Runnable mSwitchPageRunnable = new Runnable() { + private final Runnable mSwitchPageRunnable = new Runnable() { @Override public void run() { showAppropriateWidgetPage(); @@ -1438,7 +1438,7 @@ public class KeyguardHostView extends KeyguardViewBase { mAppWidgetToShow = ss.appWidgetToShow; setInsets(ss.insets); if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState); - post(mSwitchPageRunnable); + mSwitchPageRunnable.run(); } @Override @@ -1472,10 +1472,21 @@ public class KeyguardHostView extends KeyguardViewBase { } private void showAppropriateWidgetPage() { - int state = mTransportState; - ensureTransportPresentOrRemoved(state); - int pageToShow = getAppropriateWidgetPage(state); - mAppWidgetContainer.setCurrentPage(pageToShow); + final int state = mTransportState; + final boolean transportAdded = ensureTransportPresentOrRemoved(state); + final int pageToShow = getAppropriateWidgetPage(state); + if (!transportAdded) { + mAppWidgetContainer.setCurrentPage(pageToShow); + } else if (state == TRANSPORT_VISIBLE) { + // If the transport was just added, we need to wait for layout to happen before + // we can set the current page. + post(new Runnable() { + @Override + public void run() { + mAppWidgetContainer.setCurrentPage(pageToShow); + } + }); + } } /** @@ -1499,12 +1510,11 @@ public class KeyguardHostView extends KeyguardViewBase { * * @param state */ - private void ensureTransportPresentOrRemoved(int state) { + private boolean ensureTransportPresentOrRemoved(int state) { final boolean showing = getWidgetPosition(R.id.keyguard_transport_control) != -1; final boolean visible = state == TRANSPORT_VISIBLE; final boolean shouldBeVisible = state == TRANSPORT_INVISIBLE && isMusicPlaying(state); if (!showing && (visible || shouldBeVisible)) { - if (DEBUGXPORT) Log.v(TAG, "add transport"); // insert to left of camera if it exists, otherwise after right-most widget int lastWidget = mAppWidgetContainer.getChildCount() - 1; int position = 0; // handle no widget case @@ -1512,13 +1522,16 @@ public class KeyguardHostView extends KeyguardViewBase { position = mAppWidgetContainer.isCameraPage(lastWidget) ? lastWidget : lastWidget + 1; } + if (DEBUGXPORT) Log.v(TAG, "add transport at " + position); mAppWidgetContainer.addWidget(getOrCreateTransportControl(), position); + return true; } else if (showing && state == TRANSPORT_GONE) { if (DEBUGXPORT) Log.v(TAG, "remove transport"); mAppWidgetContainer.removeWidget(getOrCreateTransportControl()); mTransportControl = null; KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null); } + return false; } private CameraWidgetFrame findCameraPage() { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java index 69075ec..751572c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java @@ -177,6 +177,7 @@ class KeyguardMessageArea extends TextView { public KeyguardMessageArea(Context context, AttributeSet attrs) { super(context, attrs); + setLayerType(LAYER_TYPE_HARDWARE, null); // work around nested unclipped SaveLayer bug mLockPatternUtils = new LockPatternUtils(context); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java index 8ccd6fe..36b2446 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java @@ -68,8 +68,6 @@ public class KeyguardService extends Service { } private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() { - private boolean mSetHiddenCalled; - private boolean mIsHidden; public boolean isShowing() { return mKeyguardViewMediator.isShowing(); } @@ -91,10 +89,7 @@ public class KeyguardService extends Service { } public void setHidden(boolean isHidden) { checkPermission(); - if (mSetHiddenCalled && mIsHidden == isHidden) return; mKeyguardViewMediator.setHidden(isHidden); - mSetHiddenCalled = true; - mIsHidden = isHidden; } public void dismiss() { mKeyguardViewMediator.dismiss(); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java index e39622a..9accbb4 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java @@ -46,9 +46,10 @@ public class KeyguardSimPinView extends KeyguardAbsKeyInputView implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { private static final String LOG_TAG = "KeyguardSimPinView"; private static final boolean DEBUG = KeyguardViewMediator.DEBUG; + public static final String TAG = "KeyguardSimPinView"; private ProgressDialog mSimUnlockProgressDialog = null; - private volatile boolean mSimCheckInProgress; + private CheckSimPin mCheckSimPinThread; private AlertDialog mRemainingAttemptsDialog; @@ -169,14 +170,17 @@ public class KeyguardSimPinView extends KeyguardAbsKeyInputView @Override public void run() { try { + Log.v(TAG, "call supplyPinReportResult()"); final int[] result = ITelephony.Stub.asInterface(ServiceManager .checkService("phone")).supplyPinReportResult(mPin); + Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); post(new Runnable() { public void run() { onSimCheckResponse(result[0], result[1]); } }); } catch (RemoteException e) { + Log.e(TAG, "RemoteException for supplyPinReportResult:", e); post(new Runnable() { public void run() { onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); @@ -229,9 +233,8 @@ public class KeyguardSimPinView extends KeyguardAbsKeyInputView getSimUnlockProgressDialog().show(); - if (!mSimCheckInProgress) { - mSimCheckInProgress = true; // there should be only one - new CheckSimPin(mPasswordEntry.getText().toString()) { + if (mCheckSimPinThread == null) { + mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText().toString()) { void onSimCheckResponse(final int result, final int attemptsRemaining) { post(new Runnable() { public void run() { @@ -263,11 +266,12 @@ public class KeyguardSimPinView extends KeyguardAbsKeyInputView mPasswordEntry.setText(""); } mCallback.userActivity(0); - mSimCheckInProgress = false; + mCheckSimPinThread = null; } }); } - }.start(); + }; + mCheckSimPinThread.start(); } } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java index 31518a1..6e9e83e 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java @@ -45,9 +45,10 @@ public class KeyguardSimPukView extends KeyguardAbsKeyInputView implements KeyguardSecurityView, OnEditorActionListener, TextWatcher { private static final String LOG_TAG = "KeyguardSimPukView"; private static final boolean DEBUG = KeyguardViewMediator.DEBUG; + public static final String TAG = "KeyguardSimPukView"; private ProgressDialog mSimUnlockProgressDialog = null; - private volatile boolean mCheckInProgress; + private CheckSimPuk mCheckSimPukThread; private String mPukText; private String mPinText; private StateMachine mStateMachine = new StateMachine(); @@ -220,15 +221,17 @@ public class KeyguardSimPukView extends KeyguardAbsKeyInputView @Override public void run() { try { + Log.v(TAG, "call supplyPukReportResult()"); final int[] result = ITelephony.Stub.asInterface(ServiceManager .checkService("phone")).supplyPukReportResult(mPuk, mPin); - + Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]); post(new Runnable() { public void run() { onSimLockChangedResponse(result[0], result[1]); } }); } catch (RemoteException e) { + Log.e(TAG, "RemoteException for supplyPukReportResult:", e); post(new Runnable() { public void run() { onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); @@ -295,9 +298,8 @@ public class KeyguardSimPukView extends KeyguardAbsKeyInputView private void updateSim() { getSimUnlockProgressDialog().show(); - if (!mCheckInProgress) { - mCheckInProgress = true; - new CheckSimPuk(mPukText, mPinText) { + if (mCheckSimPukThread == null) { + mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText) { void onSimLockChangedResponse(final int result, final int attemptsRemaining) { post(new Runnable() { public void run() { @@ -326,11 +328,12 @@ public class KeyguardSimPukView extends KeyguardAbsKeyInputView + " attemptsRemaining=" + attemptsRemaining); mStateMachine.reset(); } - mCheckInProgress = false; + mCheckSimPukThread = null; } }); } - }.start(); + }; + mCheckSimPukThread.start(); } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java index d933275..0bfee38 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java @@ -98,26 +98,13 @@ public class KeyguardStatusView extends GridLayout { } protected void refresh() { - Resources res = mContext.getResources(); - Locale locale = Locale.getDefault(); - final String dateFormat = DateFormat.getBestDateTimePattern(locale, - res.getString(R.string.abbrev_wday_month_day_no_year)); - - mDateView.setFormat24Hour(dateFormat); - mDateView.setFormat12Hour(dateFormat); - - // 12-hour clock. - // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton - // format. The following code removes the AM/PM indicator if we didn't want it. - final String clock12skel = res.getString(R.string.clock_12hr_format); - String clock12hr = DateFormat.getBestDateTimePattern(locale, clock12skel); - clock12hr = clock12skel.contains("a") ? clock12hr : clock12hr.replaceAll("a", "").trim(); - mClockView.setFormat12Hour(clock12hr); - - // 24-hour clock - final String clock24skel = res.getString(R.string.clock_24hr_format); - final String clock24hr = DateFormat.getBestDateTimePattern(locale, clock24skel); - mClockView.setFormat24Hour(clock24hr); + Patterns.update(mContext); + + mDateView.setFormat24Hour(Patterns.dateView); + mDateView.setFormat12Hour(Patterns.dateView); + + mClockView.setFormat12Hour(Patterns.clockView12); + mClockView.setFormat24Hour(Patterns.clockView24); refreshAlarmStatus(); } @@ -149,4 +136,35 @@ public class KeyguardStatusView extends GridLayout { return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET; } + // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. + // This is an optimization to ensure we only recompute the patterns when the inputs change. + private static final class Patterns { + static String dateView; + static String clockView12; + static String clockView24; + static String cacheKey; + + static void update(Context context) { + final Locale locale = Locale.getDefault(); + final Resources res = context.getResources(); + final String dateViewSkel = res.getString(R.string.abbrev_wday_month_day_no_year); + final String clockView12Skel = res.getString(R.string.clock_12hr_format); + final String clockView24Skel = res.getString(R.string.clock_24hr_format); + final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel; + if (key.equals(cacheKey)) return; + + dateView = DateFormat.getBestDateTimePattern(locale, dateViewSkel); + + clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel); + // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton + // format. The following code removes the AM/PM indicator if we didn't want it. + if (!clockView12Skel.contains("a")) { + clockView12 = clockView12.replaceAll("a", "").trim(); + } + + clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); + + cacheKey = key; + } + } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java index 29ba60d..2719c5c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java @@ -104,7 +104,9 @@ public class KeyguardTransportControlView extends FrameLayout { new RemoteController.OnClientUpdateListener() { @Override public void onClientChange(boolean clearing) { - clearMetadata(); + if (clearing) { + clearMetadata(); + } } @Override @@ -206,10 +208,10 @@ public class KeyguardTransportControlView extends FrameLayout { = new KeyguardUpdateMonitorCallback() { public void onScreenTurnedOff(int why) { setEnableMarquee(false); - }; + } public void onScreenTurnedOn() { setEnableMarquee(true); - }; + } }; public KeyguardTransportControlView(Context context, AttributeSet attrs) { @@ -328,6 +330,33 @@ public class KeyguardTransportControlView extends FrameLayout { removeCallbacks(mUpdateSeekBars); } + @Override + protected Parcelable onSaveInstanceState() { + SavedState ss = new SavedState(super.onSaveInstanceState()); + ss.artist = mMetadata.artist; + ss.trackTitle = mMetadata.trackTitle; + ss.albumTitle = mMetadata.albumTitle; + ss.duration = mMetadata.duration; + ss.bitmap = mMetadata.bitmap; + return ss; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + mMetadata.artist = ss.artist; + mMetadata.trackTitle = ss.trackTitle; + mMetadata.albumTitle = ss.albumTitle; + mMetadata.duration = ss.duration; + mMetadata.bitmap = ss.bitmap; + populateMetadata(); + } + void setBadgeIcon(Drawable bmp) { mBadge.setImageDrawable(bmp); @@ -587,6 +616,11 @@ public class KeyguardTransportControlView extends FrameLayout { static class SavedState extends BaseSavedState { boolean clientPresent; + String artist; + String trackTitle; + String albumTitle; + long duration; + Bitmap bitmap; SavedState(Parcelable superState) { super(superState); @@ -594,13 +628,23 @@ public class KeyguardTransportControlView extends FrameLayout { private SavedState(Parcel in) { super(in); - this.clientPresent = in.readInt() != 0; + clientPresent = in.readInt() != 0; + artist = in.readString(); + trackTitle = in.readString(); + albumTitle = in.readString(); + duration = in.readLong(); + bitmap = Bitmap.CREATOR.createFromParcel(in); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); - out.writeInt(this.clientPresent ? 1 : 0); + out.writeInt(clientPresent ? 1 : 0); + out.writeString(artist); + out.writeString(trackTitle); + out.writeString(albumTitle); + out.writeLong(duration); + bitmap.writeToParcel(out, flags); } public static final Parcelable.Creator<SavedState> CREATOR diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index 520cea3..a849316 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -815,7 +815,7 @@ public class KeyguardUpdateMonitor { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onKeyguardVisibilityChanged(isShowing); + cb.onKeyguardVisibilityChangedRaw(isShowing); } } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 76f9637..c08880d 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -19,6 +19,7 @@ import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.graphics.Bitmap; import android.media.AudioManager; +import android.os.SystemClock; import android.view.WindowManagerPolicy; import com.android.internal.telephony.IccCardConstants; @@ -27,6 +28,11 @@ import com.android.internal.telephony.IccCardConstants; * Callback for general information relevant to lock screen. */ class KeyguardUpdateMonitorCallback { + + private static final long VISIBILITY_CHANGED_COLLAPSE_MS = 1000; + private long mVisibilityChangedCalled; + private boolean mShowing; + /** * Called when the battery status changes, e.g. when plugged in or unplugged, charge * level, etc. changes. @@ -70,6 +76,15 @@ class KeyguardUpdateMonitorCallback { */ void onKeyguardVisibilityChanged(boolean showing) { } + void onKeyguardVisibilityChangedRaw(boolean showing) { + final long now = SystemClock.elapsedRealtime(); + if (showing == mShowing + && (now - mVisibilityChangedCalled) < VISIBILITY_CHANGED_COLLAPSE_MS) return; + onKeyguardVisibilityChanged(showing); + mVisibilityChangedCalled = now; + mShowing = showing; + } + /** * Called when visibility of lockscreen clock changes, such as when * obscured by a widget. diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java index 8e39628..f0413d6 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java @@ -15,6 +15,9 @@ */ package com.android.keyguard; +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; import android.os.Handler; import android.os.Looper; import android.util.Log; @@ -46,6 +49,20 @@ public class KeyguardViewStateManager implements int mChallengeTop = 0; + private final AnimatorListener mPauseListener = new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { + mKeyguardSecurityContainer.onPause(); + } + }; + + private final AnimatorListener mResumeListener = new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { + if (((View)mKeyguardSecurityContainer).isShown()) { + mKeyguardSecurityContainer.onResume(0); + } + } + }; + public KeyguardViewStateManager(KeyguardHostView hostView) { mKeyguardHostView = hostView; } @@ -102,20 +119,20 @@ public class KeyguardViewStateManager implements } public void fadeOutSecurity(int duration) { - ((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration).start(); + ((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration) + .setListener(mPauseListener); } public void fadeInSecurity(int duration) { - ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration).start(); + ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration) + .setListener(mResumeListener); } public void onPageBeginMoving() { if (mChallengeLayout.isChallengeOverlapping() && mChallengeLayout instanceof SlidingChallengeLayout) { SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout; - if (!mKeyguardWidgetPager.isWarping()) { - scl.fadeOutChallenge(); - } + scl.fadeOutChallenge(); mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage(); } // We use mAppWidgetToShow to show a particular widget after you add it-- @@ -139,9 +156,6 @@ public class KeyguardViewStateManager implements boolean isCameraPage = newPage instanceof CameraWidgetFrame; SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout; scl.setChallengeInteractive(!isCameraPage); - if (isCameraPage) { - scl.fadeOutChallenge(); - } final int currentFlags = mKeyguardWidgetPager.getSystemUiVisibility(); final int newFlags = isCameraPage ? (currentFlags | View.STATUS_BAR_DISABLE_SEARCH) : (currentFlags & ~View.STATUS_BAR_DISABLE_SEARCH); @@ -178,7 +192,7 @@ public class KeyguardViewStateManager implements boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping(); if (challengeOverlapping && !newCurPage.isSmall() && mPageListeningToSlider != newPageIndex) { - newCurPage.shrinkWidget(); + newCurPage.shrinkWidget(true); } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java index ab8a759..8ee9b61 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java @@ -375,10 +375,6 @@ public class KeyguardWidgetFrame extends FrameLayout { return mSmallFrameHeight; } - public void shrinkWidget() { - shrinkWidget(true); - } - public void setWidgetLockedSmall(boolean locked) { if (locked) { setWidgetHeight(mSmallWidgetHeight); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java index 704af6e..99f7757 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java @@ -194,7 +194,9 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit @Override public void onPageEndWarp() { - hideOutlinesAndSidePages(); + // if we're moving to the warp page, then immediately hide the other widgets. + int duration = getPageWarpIndex() == getNextPage() ? 0 : -1; + animateOutlinesAndSidePages(false, duration); mViewStateManager.onPageEndWarp(); } @@ -669,7 +671,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit // On the very first measure pass, if the challenge is showing, we need to make sure // that the widget on the current page is small. if (challengeShowing && i == mCurrentPage && !mHasMeasure) { - frame.shrinkWidget(); + frame.shrinkWidget(true); } } } diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java index 9d237dc..b9404d4 100644 --- a/packages/Keyguard/src/com/android/keyguard/PagedView.java +++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java @@ -267,6 +267,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private boolean mIsCameraEvent; private float mWarpPeekAmount; + private boolean mOnPageEndWarpCalled; + private boolean mOnPageBeginWarpCalled; public interface PageSwitchListener { void onPageSwitching(View newPage, int newPageIndex); @@ -491,7 +493,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (!mIsPageMoving) { mIsPageMoving = true; if (isWarping()) { - onPageBeginWarp(); + dispatchOnPageBeginWarp(); if (mPageSwapIndex != -1) { swapPages(mPageSwapIndex, mPageWarpIndex); } @@ -500,6 +502,22 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } + private void dispatchOnPageBeginWarp() { + if (!mOnPageBeginWarpCalled) { + onPageBeginWarp(); + mOnPageBeginWarpCalled = true; + } + mOnPageEndWarpCalled = false; + } + + private void dispatchOnPageEndWarp() { + if (!mOnPageEndWarpCalled) { + onPageEndWarp(); + mOnPageEndWarpCalled = true; + } + mOnPageBeginWarpCalled = false; + } + protected void pageEndMoving() { if (DEBUG_WARP) Log.v(TAG, "pageEndMoving(" + mIsPageMoving + ")"); if (mIsPageMoving) { @@ -508,7 +526,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mPageSwapIndex != -1) { swapPages(mPageSwapIndex, mPageWarpIndex); } - onPageEndWarp(); + dispatchOnPageEndWarp(); resetPageWarp(); } onPageEndMoving(); @@ -1919,7 +1937,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } if (isWarping()) { - onPageEndWarp(); + dispatchOnPageEndWarp(); resetPageWarp(); } @@ -2260,11 +2278,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mTempVisiblePagesRange[0] = 0; mTempVisiblePagesRange[1] = getPageCount() - 1; boundByReorderablePages(true, mTempVisiblePagesRange); - mReorderingStarted = true; // Check if we are within the reordering range if (mTempVisiblePagesRange[0] <= dragViewIndex && dragViewIndex <= mTempVisiblePagesRange[1]) { + mReorderingStarted = true; if (zoomOut()) { // Find the drag view under the pointer mDragView = getChildAt(dragViewIndex); @@ -2702,12 +2720,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override public void onAnimationEnd(Animator animation) { mWarpAnimation = null; - mWarpPageExposed = true; + mWarpPageExposed = false; } }; private void cancelWarpAnimation(String msg, boolean abortAnimation) { - if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ")"); + if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ",abort=" + abortAnimation + ")"); if (abortAnimation) { // We're done with the animation and moving to a new page. Let the scroller // take over the animation. @@ -2727,9 +2745,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private void animateWarpPageOnScreen(String reason) { if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen(" + reason + ")"); - if (isWarping()) { + if (isWarping() && !mWarpPageExposed) { mWarpPageExposed = true; - onPageBeginWarp(); + dispatchOnPageBeginWarp(); KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex); if (DEBUG_WARP) Log.v(TAG, "moving page on screen: Tx=" + v.getTranslationX()); DecelerateInterpolator interp = new DecelerateInterpolator(1.5f); @@ -2744,7 +2762,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private void animateWarpPageOffScreen(String reason, boolean animate) { if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen(" + reason + " anim:" + animate + ")"); if (isWarping()) { - onPageEndWarp(); + dispatchOnPageEndWarp(); KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex); if (DEBUG_WARP) Log.v(TAG, "moving page off screen: Tx=" + v.getTranslationX()); AccelerateInterpolator interp = new AccelerateInterpolator(1.5f); diff --git a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java index 7a9a1c8..3d515ce 100644 --- a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java +++ b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java @@ -1003,6 +1003,16 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout } } + @Override + protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { + // Focus security fileds before widgets. + if (mChallengeView != null && + mChallengeView.requestFocus(direction, previouslyFocusedRect)) { + return true; + } + return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); + } + public void computeScroll() { super.computeScroll(); diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index f2e768a..d2613d0 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -93,6 +93,12 @@ <!-- Title of the action bar button to got to add a printer. [CHAR LIMIT=25] --> <string name="print_add_printer">Add printer</string> + <!-- Title of the menu item to select a printer. [CHAR LIMIT=25] --> + <string name="print_select_printer">Select printer</string> + + <!-- Title of the menu item to forget a printer. [CHAR LIMIT=25] --> + <string name="print_forget_printer">Forget printer</string> + <!-- Utterance to announce a change in the number of matches during a search. This is spoken to a blind user. [CHAR LIMIT=none] --> <plurals name="print_search_result_count_utterance"> <item quantity="one"><xliff:g id="count" example="1">%1$s</xliff:g> printer found</item> diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java index 0601467..9831839 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java +++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java @@ -79,6 +79,8 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { private PrinterId mTrackedPrinter; + private boolean mPrintersUpdatedBefore; + public FusedPrintersProvider(Context context) { super(context); mPersistenceManager = new PersistenceManager(context); @@ -88,13 +90,14 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { mPersistenceManager.addPrinterAndWritePrinterHistory(printer); } - private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters) { + private void computeAndDeliverResult(ArrayMap<PrinterId, PrinterInfo> discoveredPrinters, + ArrayMap<PrinterId, PrinterInfo> favoritePrinters) { List<PrinterInfo> printers = new ArrayList<PrinterInfo>(); // Add the updated favorite printers. - final int favoritePrinterCount = mFavoritePrinters.size(); + final int favoritePrinterCount = favoritePrinters.size(); for (int i = 0; i < favoritePrinterCount; i++) { - PrinterInfo favoritePrinter = mFavoritePrinters.get(i); + PrinterInfo favoritePrinter = favoritePrinters.valueAt(i); PrinterInfo updatedPrinter = discoveredPrinters.remove( favoritePrinter.getId()); if (updatedPrinter != null) { @@ -123,8 +126,11 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { mPrinters.addAll(printers); if (isStarted()) { - // Deliver the printers. + // If stated deliver the new printers. deliverResult(printers); + } else { + // Otherwise, take a note for the change. + onContentChanged(); } } @@ -165,6 +171,8 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { .getSystemService(Context.PRINT_SERVICE); mDiscoverySession = printManager.createPrinterDiscoverySession(); mPersistenceManager.readPrinterHistory(); + } else if (mPersistenceManager.isHistoryChanged()) { + mPersistenceManager.readPrinterHistory(); } if (mPersistenceManager.isReadHistoryCompleted() && !mDiscoverySession.isPrinterDiscoveryStarted()) { @@ -176,7 +184,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { + mDiscoverySession.getPrinters().size() + " " + FusedPrintersProvider.this.hashCode()); } - updatePrinters(mDiscoverySession.getPrinters()); + updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters); } }); final int favoriteCount = mFavoritePrinters.size(); @@ -187,15 +195,19 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { mDiscoverySession.startPrinterDisovery(printerIds); List<PrinterInfo> printers = mDiscoverySession.getPrinters(); if (!printers.isEmpty()) { - updatePrinters(printers); + updatePrinters(printers, mFavoritePrinters); } } } - private void updatePrinters(List<PrinterInfo> printers) { - if (mPrinters.equals(printers)) { + private void updatePrinters(List<PrinterInfo> printers, List<PrinterInfo> favoritePrinters) { + if (mPrintersUpdatedBefore && mPrinters.equals(printers) + && mFavoritePrinters.equals(favoritePrinters)) { return; } + + mPrintersUpdatedBefore = true; + ArrayMap<PrinterId, PrinterInfo> printersMap = new ArrayMap<PrinterId, PrinterInfo>(); final int printerCount = printers.size(); @@ -203,7 +215,16 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { PrinterInfo printer = printers.get(i); printersMap.put(printer.getId(), printer); } - computeAndDeliverResult(printersMap); + + ArrayMap<PrinterId, PrinterInfo> favoritePrintersMap = + new ArrayMap<PrinterId, PrinterInfo>(); + final int favoritePrinterCount = favoritePrinters.size(); + for (int i = 0; i < favoritePrinterCount; i++) { + PrinterInfo favoritePrinter = favoritePrinters.get(i); + favoritePrintersMap.put(favoritePrinter.getId(), favoritePrinter); + } + + computeAndDeliverResult(printersMap, favoritePrintersMap); } @Override @@ -264,6 +285,42 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { } } + public boolean isFavoritePrinter(PrinterId printerId) { + final int printerCount = mFavoritePrinters.size(); + for (int i = 0; i < printerCount; i++) { + PrinterInfo favoritePritner = mFavoritePrinters.get(i); + if (favoritePritner.getId().equals(printerId)) { + return true; + } + } + return false; + } + + public void forgetFavoritePrinter(PrinterId printerId) { + List<PrinterInfo> newFavoritePrinters = null; + + // Remove the printer from the favorites. + final int favoritePrinterCount = mFavoritePrinters.size(); + for (int i = 0; i < favoritePrinterCount; i++) { + PrinterInfo favoritePrinter = mFavoritePrinters.get(i); + if (favoritePrinter.getId().equals(printerId)) { + newFavoritePrinters = new ArrayList<PrinterInfo>(); + newFavoritePrinters.addAll(mPrinters); + newFavoritePrinters.remove(i); + break; + } + } + + // If we removed a favorite printer, we have work to do. + if (newFavoritePrinters != null) { + // Remove the printer from history and persist the latter. + mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId); + + // Recompute and deliver the printers. + updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters); + } + } + private final class PersistenceManager { private static final String PERSIST_FILE_NAME = "printer_history.xml"; @@ -281,13 +338,15 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { private final AtomicFile mStatePersistFile; - private List<PrinterInfo> mHistoricalPrinters; + private List<PrinterInfo> mHistoricalPrinters = new ArrayList<PrinterInfo>(); private boolean mReadHistoryCompleted; private boolean mReadHistoryInProgress; private ReadTask mReadTask; + private volatile long mLastReadHistoryTimestamp; + private PersistenceManager(Context context) { mStatePersistFile = new AtomicFile(new File(context.getFilesDir(), PERSIST_FILE_NAME)); @@ -327,6 +386,27 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { new ArrayList<PrinterInfo>(mHistoricalPrinters)); } + @SuppressWarnings("unchecked") + public void removeHistoricalPrinterAndWritePrinterHistory(PrinterId printerId) { + boolean writeHistory = false; + final int printerCount = mHistoricalPrinters.size(); + for (int i = printerCount - 1; i >= 0; i--) { + PrinterInfo historicalPrinter = mHistoricalPrinters.get(i); + if (historicalPrinter.getId().equals(printerId)) { + mHistoricalPrinters.remove(i); + writeHistory = true; + } + } + if (writeHistory) { + new WriteTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, + new ArrayList<PrinterInfo>(mHistoricalPrinters)); + } + } + + public boolean isHistoryChanged() { + return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified(); + } + private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) { Map<PrinterId, PrinterRecord> recordMap = new ArrayMap<PrinterId, PrinterRecord>(); @@ -423,11 +503,10 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { mReadHistoryInProgress = false; mReadHistoryCompleted = true; - // Deliver the favorites. - Map<PrinterId, PrinterInfo> discoveredPrinters = Collections.emptyMap(); - computeAndDeliverResult(discoveredPrinters); + // Deliver the printers. + updatePrinters(mDiscoverySession.getPrinters(), mHistoricalPrinters); - // Start loading the available printers. + // Loading the available printers if needed. loadInternal(); // We are done. @@ -450,6 +529,8 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, null); parseState(parser, printers); + // Take a note which version of the history was read. + mLastReadHistoryTimestamp = mStatePersistFile.getBaseFile().lastModified(); return printers; } catch (IllegalStateException ise) { Slog.w(LOG_TAG, "Failed parsing ", ise); diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index 8f26361..88403a3 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -357,6 +357,9 @@ public class PrintJobConfigActivity extends Activity { } public void cancel() { + if (isWorking()) { + mRemotePrintAdapter.cancel(); + } mControllerState = CONTROLLER_STATE_CANCELLED; } @@ -934,6 +937,7 @@ public class PrintJobConfigActivity extends Activity { mPrintJobId, mCurrentPrinter); if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) { + mCapabilitiesTimeout.post(); updateUi(); return; } diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java index 609ae64..778fb4d 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java @@ -544,7 +544,7 @@ public final class PrintSpoolerService extends Service { final int printJobCount = mPrintJobs.size(); for (int i = 0; i < printJobCount; i++) { PrintJobInfo printJob = mPrintJobs.get(i); - if (isActiveState(printJob.getState()) + if (isActiveState(printJob.getState()) && printJob.getPrinterId() != null && printJob.getPrinterId().getServiceName().equals(service)) { return true; } diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java index fd14af9..d9ccb5d 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java +++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java @@ -137,4 +137,15 @@ final class RemotePrintDocumentAdapter { Log.e(LOG_TAG, "Error calling finish()", re); } } + + public void cancel() { + if (DEBUG) { + Log.i(LOG_TAG, "cancel()"); + } + try { + mRemoteInterface.cancel(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling cancel()", re); + } + } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java index 204c152..fe5920c 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java +++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java @@ -46,6 +46,8 @@ import android.printservice.PrintServiceInfo; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -54,6 +56,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.Filter; @@ -81,6 +84,8 @@ public final class SelectPrinterFragment extends Fragment { private static final String FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS = "FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS"; + private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID"; + private final ArrayList<PrintServiceInfo> mAddPrinterServices = new ArrayList<PrintServiceInfo>(); @@ -127,6 +132,9 @@ public final class SelectPrinterFragment extends Fragment { mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + if (!((DestinationAdapter) mListView.getAdapter()).isActionable(position)) { + return; + } PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position); Activity activity = getActivity(); if (activity instanceof OnPrinterSelectedListener) { @@ -138,6 +146,8 @@ public final class SelectPrinterFragment extends Fragment { } }); + registerForContextMenu(mListView); + return content; } @@ -185,6 +195,62 @@ public final class SelectPrinterFragment extends Fragment { } @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { + if (view == mListView) { + final int position = ((AdapterContextMenuInfo) menuInfo).position; + PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position); + + menu.setHeaderTitle(printer.getName()); + + // Add the select menu item if applicable. + if (printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE) { + MenuItem selectItem = menu.add(Menu.NONE, R.string.print_select_printer, + Menu.NONE, R.string.print_select_printer); + Intent intent = new Intent(); + intent.putExtra(EXTRA_PRINTER_ID, printer.getId()); + selectItem.setIntent(intent); + } + + // Add the forget menu item if applicable. + FusedPrintersProvider provider = (FusedPrintersProvider) (Loader<?>) + getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER); + if (provider.isFavoritePrinter(printer.getId())) { + MenuItem forgetItem = menu.add(Menu.NONE, R.string.print_forget_printer, + Menu.NONE, R.string.print_forget_printer); + Intent intent = new Intent(); + intent.putExtra(EXTRA_PRINTER_ID, printer.getId()); + forgetItem.setIntent(intent); + } + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.string.print_select_printer: { + PrinterId printerId = (PrinterId) item.getIntent().getParcelableExtra( + EXTRA_PRINTER_ID); + Activity activity = getActivity(); + if (activity instanceof OnPrinterSelectedListener) { + ((OnPrinterSelectedListener) activity).onPrinterSelected(printerId); + } else { + throw new IllegalStateException("the host activity must implement" + + " OnPrinterSelectedListener"); + } + } return true; + + case R.string.print_forget_printer: { + PrinterId printerId = (PrinterId) item.getIntent().getParcelableExtra( + EXTRA_PRINTER_ID); + FusedPrintersProvider provider = (FusedPrintersProvider) (Loader<?>) + getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER); + provider.forgetFavoritePrinter(printerId); + } return true; + } + return false; + } + + @Override public void onResume() { updateAddPrintersAdapter(); getActivity().invalidateOptionsMenu(); @@ -464,7 +530,7 @@ public final class SelectPrinterFragment extends Fragment { R.layout.printer_list_item, parent, false); } - convertView.setEnabled(isEnabled(position)); + convertView.setEnabled(isActionable(position)); CharSequence title = null; CharSequence subtitle = null; @@ -506,8 +572,7 @@ public final class SelectPrinterFragment extends Fragment { return convertView; } - @Override - public boolean isEnabled(int position) { + public boolean isActionable(int position) { PrinterInfo printer = (PrinterInfo) getItem(position); return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE; } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index ffb4c20..29e8d1d 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -5,7 +5,6 @@ > <!-- Standard permissions granted to the shell. --> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> @@ -64,6 +63,7 @@ <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.MANAGE_USERS" /> diff --git a/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..5bbfa4f --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png Binary files differindex 2d8d074..693abf5 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png Binary files differindex 7220968..e3b3eeb 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png Binary files differindex 8f4cb64..c6f03c4 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png diff --git a/packages/SystemUI/res/drawable-hdpi/search_light.png b/packages/SystemUI/res/drawable-hdpi/search_light.png Binary files differindex 116b1f0..3c0dc4e 100644 --- a/packages/SystemUI/res/drawable-hdpi/search_light.png +++ b/packages/SystemUI/res/drawable-hdpi/search_light.png diff --git a/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..1a58144 --- /dev/null +++ b/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..a12519e --- /dev/null +++ b/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..ce41454 --- /dev/null +++ b/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..b0b4561 --- /dev/null +++ b/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..2856e09 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png Binary files differindex 399db00..15340d3 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png Binary files differindex 8c2dc68..cc81794 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png Binary files differindex 2142147..1c2d7aa 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png diff --git a/packages/SystemUI/res/drawable-mdpi/search_light.png b/packages/SystemUI/res/drawable-mdpi/search_light.png Binary files differindex 7a70984..8010ce7 100644 --- a/packages/SystemUI/res/drawable-mdpi/search_light.png +++ b/packages/SystemUI/res/drawable-mdpi/search_light.png diff --git a/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..72269f2 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png Binary files differindex c0032e2..e3cc9b0 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png Binary files differindex bffbf55..65d15b5 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png Binary files differindex b0ea8e0..fbd4d6b 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png diff --git a/packages/SystemUI/res/drawable-xhdpi/search_light.png b/packages/SystemUI/res/drawable-xhdpi/search_light.png Binary files differindex e2aed09..6d46fdd 100644 --- a/packages/SystemUI/res/drawable-xhdpi/search_light.png +++ b/packages/SystemUI/res/drawable-xhdpi/search_light.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png Binary files differnew file mode 100644 index 0000000..efc9b04 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png Binary files differindex a3cc08d..e15981a 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png Binary files differindex ab841d2..1a5d26a 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png Binary files differindex aac3428..86df881 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_light.png b/packages/SystemUI/res/drawable-xxhdpi/search_light.png Binary files differindex e5ef85d..7742207 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/search_light.png +++ b/packages/SystemUI/res/drawable-xxhdpi/search_light.png diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml index b2ba25a..0c0be29 100644 --- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml +++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml @@ -24,6 +24,7 @@ android:id="@+id/recents_root" android:layout_height="match_parent" android:layout_width="match_parent" + android:foreground="@drawable/bg_protect" systemui:recentItemLayout="@layout/status_bar_recent_item" > <FrameLayout diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index d7312df..eb66908 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -95,12 +95,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" /> - <!-- battery must be padded below by 2px to match assets --> + <!-- battery must be padded below to match assets --> <com.android.systemui.BatteryMeterView android:id="@+id/battery" android:layout_height="16dp" android:layout_width="10.5dp" - android:layout_marginBottom="2px" + android:layout_marginBottom="0.33dp" android:layout_marginStart="4dip" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml index e41475b..2f3968d 100644 --- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml +++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml @@ -24,6 +24,7 @@ android:id="@+id/recents_root" android:layout_height="match_parent" android:layout_width="match_parent" + android:foreground="@drawable/bg_protect" systemui:recentItemLayout="@layout/status_bar_recent_item" > <FrameLayout diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index b6e03e1..13aafb2 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -66,7 +66,7 @@ public class BatteryMeterView extends View implements DemoMode { private final RectF mFrame = new RectF(); private final RectF mButtonFrame = new RectF(); private final RectF mClipFrame = new RectF(); - private final Rect mBoltFrame = new Rect(); + private final RectF mBoltFrame = new RectF(); private class BatteryTracker extends BroadcastReceiver { public static final int UNKNOWN_LEVEL = -1; @@ -319,10 +319,10 @@ public class BatteryMeterView extends View implements DemoMode { if (tracker.plugged) { // draw the bolt - final int bl = (int)(mFrame.left + mFrame.width() / 4.5f); - final int bt = (int)(mFrame.top + mFrame.height() / 6f); - final int br = (int)(mFrame.right - mFrame.width() / 7f); - final int bb = (int)(mFrame.bottom - mFrame.height() / 10f); + final float bl = mFrame.left + mFrame.width() / 4.5f; + final float bt = mFrame.top + mFrame.height() / 6f; + final float br = mFrame.right - mFrame.width() / 7f; + final float bb = mFrame.bottom - mFrame.height() / 10f; if (mBoltFrame.left != bl || mBoltFrame.top != bt || mBoltFrame.right != br || mBoltFrame.bottom != bb) { mBoltFrame.set(bl, bt, br, bb); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 6a2bc5f..ed00398 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar; import android.app.ActivityManager; import android.app.ActivityManagerNative; -import android.app.KeyguardManager; import android.app.Notification; import android.app.PendingIntent; import android.app.TaskStackBuilder; @@ -70,6 +69,7 @@ import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SearchPanelView; import com.android.systemui.SystemUI; +import com.android.systemui.statusbar.phone.KeyguardTouchDelegate; import com.android.systemui.statusbar.policy.NotificationRowLayout; import java.util.ArrayList; @@ -128,7 +128,6 @@ public abstract class BaseStatusBar extends SystemUI implements protected boolean mUseHeadsUp = false; protected IDreamManager mDreamManager; - KeyguardManager mKeyguardManager; PowerManager mPowerManager; protected int mRowHeight; @@ -221,7 +220,6 @@ public abstract class BaseStatusBar extends SystemUI implements mDreamManager = IDreamManager.Stub.asInterface( ServiceManager.checkService(DreamService.DREAM_SERVICE)); - mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mProvisioningObserver.onChange(false); // set up @@ -749,9 +747,7 @@ public abstract class BaseStatusBar extends SystemUI implements Log.w(TAG, "Sending contentIntent failed: " + e); } - KeyguardManager kgm = - (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); - if (kgm != null) kgm.exitKeyguardSecurely(null); + KeyguardTouchDelegate.getInstance(mContext).dismiss(); } try { @@ -1056,10 +1052,12 @@ public abstract class BaseStatusBar extends SystemUI implements boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP, Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER; + final KeyguardTouchDelegate keyguard = KeyguardTouchDelegate.getInstance(mContext); boolean interrupt = (isFullscreen || (isHighPriority && isNoisy)) && isAllowed && mPowerManager.isScreenOn() - && !mKeyguardManager.isKeyguardLocked(); + && !keyguard.isShowingAndNotHidden() + && !keyguard.isInputRestricted(); try { interrupt = interrupt && !mDreamManager.isDreaming(); } catch (RemoteException e) { @@ -1087,8 +1085,7 @@ public abstract class BaseStatusBar extends SystemUI implements } public boolean inKeyguardRestrictedInputMode() { - KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); - return km.inKeyguardRestrictedInputMode(); + return KeyguardTouchDelegate.getInstance(mContext).isInputRestricted(); } public void setInteracting(int barWindow, boolean interacting) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index e8173b7..39333d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -55,8 +55,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final int MSG_TOGGLE_RECENT_APPS = 13 << MSG_SHIFT; private static final int MSG_PRELOAD_RECENT_APPS = 14 << MSG_SHIFT; private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 15 << MSG_SHIFT; - private static final int MSG_SET_NAVIGATION_ICON_HINTS = 16 << MSG_SHIFT; - private static final int MSG_SET_WINDOW_STATE = 17 << MSG_SHIFT; + private static final int MSG_SET_WINDOW_STATE = 16 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -98,7 +97,6 @@ public class CommandQueue extends IStatusBar.Stub { public void showSearchPanel(); public void hideSearchPanel(); public void cancelPreloadRecentApps(); - public void setNavigationIconHints(int hints); public void setWindowState(int window, int state); } @@ -227,13 +225,6 @@ public class CommandQueue extends IStatusBar.Stub { } } - public void setNavigationIconHints(int hints) { - synchronized (mList) { - mHandler.removeMessages(MSG_SET_NAVIGATION_ICON_HINTS); - mHandler.obtainMessage(MSG_SET_NAVIGATION_ICON_HINTS, hints, 0, null).sendToTarget(); - } - } - public void setWindowState(int window, int state) { synchronized (mList) { // don't coalesce these @@ -318,9 +309,6 @@ public class CommandQueue extends IStatusBar.Stub { case MSG_CANCEL_PRELOAD_RECENT_APPS: mCallbacks.cancelPreloadRecentApps(); break; - case MSG_SET_NAVIGATION_ICON_HINTS: - mCallbacks.setNavigationIconHints(msg.arg1); - break; case MSG_SET_WINDOW_STATE: mCallbacks.setWindowState(msg.arg1, msg.arg2); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java index 8ad538b..cb17ac6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java @@ -99,6 +99,10 @@ public class BarTransitions { mBarBackground.finishAnimation(); } + public void setContentVisible(boolean visible) { + // for subclasses + } + private static class BarBackgroundDrawable extends Drawable { private final int mOpaque; private final int mSemiTransparent; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java index 5c55f0d..c1646ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java @@ -77,10 +77,11 @@ public class KeyguardTouchDelegate { } public static KeyguardTouchDelegate getInstance(Context context) { - if (sInstance == null) { - sInstance = new KeyguardTouchDelegate(context); + KeyguardTouchDelegate instance = sInstance; + if (instance == null) { + instance = sInstance = new KeyguardTouchDelegate(context); } - return sInstance; + return instance; } public boolean isSecure() { @@ -165,7 +166,21 @@ public class KeyguardTouchDelegate { Slog.e(TAG, "RemoteException launching camera!", e); } } else { - Slog.w(TAG, "dispatch(event): NO SERVICE!"); + Slog.w(TAG, "launchCamera(): NO SERVICE!"); + } + } + + public void dismiss() { + final IKeyguardService service = mService; + if (service != null) { + try { + service.dismiss(); + } catch (RemoteException e) { + // What to do? + Slog.e(TAG, "RemoteException dismissing keyguard!", e); + } + } else { + Slog.w(TAG, "dismiss(): NO SERVICE!"); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java index 5d4b995..a74230b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java @@ -30,6 +30,9 @@ import com.android.systemui.statusbar.policy.KeyButtonView; public final class NavigationBarTransitions extends BarTransitions { + private static final float KEYGUARD_QUIESCENT_ALPHA = 0.5f; + private static final int CONTENT_FADE_DURATION = 200; + private final NavigationBarView mView; private final IStatusBarService mBarService; @@ -73,18 +76,57 @@ public final class NavigationBarTransitions extends BarTransitions { private void applyMode(int mode, boolean animate, boolean force) { // apply to key buttons - final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT; - final float alpha = isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f; - setKeyButtonViewQuiescentAlpha(mView.getBackButton(), alpha, animate); + final float alpha = alphaForMode(mode); setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate); setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate); setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate); - setKeyButtonViewQuiescentAlpha(mView.getCameraButton(), alpha, animate); + + setKeyButtonViewQuiescentAlpha(mView.getSearchLight(), KEYGUARD_QUIESCENT_ALPHA, animate); + setKeyButtonViewQuiescentAlpha(mView.getCameraButton(), KEYGUARD_QUIESCENT_ALPHA, animate); + + applyBackButtonQuiescentAlpha(mode, animate); // apply to lights out applyLightsOut(mode == MODE_LIGHTS_OUT, animate, force); } + private float alphaForMode(int mode) { + final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT; + return isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f; + } + + public void applyBackButtonQuiescentAlpha(int mode, boolean animate) { + float backAlpha = 0; + backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getSearchLight()); + backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getCameraButton()); + backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getHomeButton()); + backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getRecentsButton()); + backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getMenuButton()); + if (backAlpha > 0) { + setKeyButtonViewQuiescentAlpha(mView.getBackButton(), backAlpha, animate); + } + } + + private static float maxVisibleQuiescentAlpha(float max, View v) { + if ((v instanceof KeyButtonView) && v.isShown()) { + return Math.max(max, ((KeyButtonView)v).getQuiescentAlpha()); + } + return max; + } + + @Override + public void setContentVisible(boolean visible) { + final float alpha = visible ? 1 : 0; + fadeContent(mView.getCameraButton(), alpha); + fadeContent(mView.getSearchLight(), alpha); + } + + private void fadeContent(View v, float alpha) { + if (v != null) { + v.animate().alpha(alpha).setDuration(CONTENT_FADE_DURATION); + } + } + private void setKeyButtonViewQuiescentAlpha(View button, float alpha, boolean animate) { if (button instanceof KeyButtonView) { ((KeyButtonView) button).setQuiescentAlpha(alpha, animate); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index d1c4109..839016d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -17,6 +17,10 @@ package com.android.systemui.statusbar.phone; import android.animation.LayoutTransition; +import android.animation.LayoutTransition.TransitionListener; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; import android.app.ActivityManagerNative; import android.app.StatusBarManager; import android.app.admin.DevicePolicyManager; @@ -48,12 +52,12 @@ import com.android.systemui.R; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.DelegateViewHelper; import com.android.systemui.statusbar.policy.DeadZone; +import com.android.systemui.statusbar.policy.KeyButtonView; import java.io.FileDescriptor; import java.io.PrintWriter; public class NavigationBarView extends LinearLayout { - private static final int CAMERA_BUTTON_FADE_DURATION = 200; final static boolean DEBUG = false; final static String TAG = "PhoneStatusBar/NavigationBarView"; @@ -89,6 +93,54 @@ public class NavigationBarView extends LinearLayout { // used to disable the camera icon in navbar when disabled by DPM private boolean mCameraDisabledByDpm; + // performs manual animation in sync with layout transitions + private final NavTransitionListener mTransitionListener = new NavTransitionListener(); + + private class NavTransitionListener implements TransitionListener { + private boolean mBackTransitioning; + private boolean mHomeAppearing; + private long mStartDelay; + private long mDuration; + private TimeInterpolator mInterpolator; + + @Override + public void startTransition(LayoutTransition transition, ViewGroup container, + View view, int transitionType) { + if (view.getId() == R.id.back) { + mBackTransitioning = true; + } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) { + mHomeAppearing = true; + mStartDelay = transition.getStartDelay(transitionType); + mDuration = transition.getDuration(transitionType); + mInterpolator = transition.getInterpolator(transitionType); + } + } + + @Override + public void endTransition(LayoutTransition transition, ViewGroup container, + View view, int transitionType) { + if (view.getId() == R.id.back) { + mBackTransitioning = false; + } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) { + mHomeAppearing = false; + } + } + + public void onBackAltCleared() { + // When dismissing ime during unlock, force the back button to run the same appearance + // animation as home (if we catch this condition early enough). + if (!mBackTransitioning && getBackButton().getVisibility() == VISIBLE + && mHomeAppearing && getHomeButton().getAlpha() == 0) { + getBackButton().setAlpha(0); + ValueAnimator a = ObjectAnimator.ofFloat(getBackButton(), "alpha", 0, 1); + a.setStartDelay(mStartDelay); + a.setDuration(mDuration); + a.setInterpolator(mInterpolator); + a.start(); + } + } + } + // simplified click handler to be used when device is in accessibility mode private final OnClickListener mAccessibilityClickListener = new OnClickListener() { @Override @@ -108,12 +160,12 @@ public class NavigationBarView extends LinearLayout { case MotionEvent.ACTION_DOWN: // disable search gesture while interacting with camera mDelegateHelper.setDisabled(true); - transitionCameraAndSearchButtonAlpha(0.0f); + mBarTransitions.setContentVisible(false); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mDelegateHelper.setDisabled(false); - transitionCameraAndSearchButtonAlpha(1.0f); + mBarTransitions.setContentVisible(true); break; } return KeyguardTouchDelegate.getInstance(getContext()).dispatch(event); @@ -163,17 +215,6 @@ public class NavigationBarView extends LinearLayout { watchForDevicePolicyChanges(); } - protected void transitionCameraAndSearchButtonAlpha(float alpha) { - View cameraButtonView = getCameraButton(); - if (cameraButtonView != null) { - cameraButtonView.animate().alpha(alpha).setDuration(CAMERA_BUTTON_FADE_DURATION); - } - View searchLight = getSearchLight(); - if (searchLight != null) { - searchLight.animate().alpha(alpha).setDuration(CAMERA_BUTTON_FADE_DURATION); - } - } - private void watchForDevicePolicyChanges() { final IntentFilter filter = new IntentFilter(); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); @@ -277,7 +318,10 @@ public class NavigationBarView extends LinearLayout { public void setNavigationIconHints(int hints, boolean force) { if (!force && hints == mNavigationIconHints) return; - + final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; + if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) { + mTransitionListener.onBackAltCleared(); + } if (DEBUG) { android.widget.Toast.makeText(mContext, "Navigation icon hints = " + hints, @@ -286,15 +330,7 @@ public class NavigationBarView extends LinearLayout { mNavigationIconHints = hints; - getBackButton().setAlpha( - (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f); - getHomeButton().setAlpha( - (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f); - getRecentsButton().setAlpha( - (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f); - - ((ImageView)getBackButton()).setImageDrawable( - (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT)) + ((ImageView)getBackButton()).setImageDrawable(backAlt ? (mVertical ? mBackAltLandIcon : mBackAltIcon) : (mVertical ? mBackLandIcon : mBackIcon)); @@ -322,13 +358,20 @@ public class NavigationBarView extends LinearLayout { setSlippery(disableHome && disableRecent && disableBack && disableSearch); } - if (!mScreenOn && mCurrentView != null) { - ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons); - LayoutTransition lt = navButtons == null ? null : navButtons.getLayoutTransition(); + ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons); + if (navButtons != null) { + LayoutTransition lt = navButtons.getLayoutTransition(); if (lt != null) { - lt.disableTransitionType( - LayoutTransition.CHANGE_APPEARING | LayoutTransition.CHANGE_DISAPPEARING | - LayoutTransition.APPEARING | LayoutTransition.DISAPPEARING); + if (!lt.getTransitionListeners().contains(mTransitionListener)) { + lt.addTransitionListener(mTransitionListener); + } + if (!mScreenOn && mCurrentView != null) { + lt.disableTransitionType( + LayoutTransition.CHANGE_APPEARING | + LayoutTransition.CHANGE_DISAPPEARING | + LayoutTransition.APPEARING | + LayoutTransition.DISAPPEARING); + } } } @@ -336,12 +379,17 @@ public class NavigationBarView extends LinearLayout { getHomeButton() .setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE); getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE); - final boolean shouldShowSearch = disableHome && !disableSearch; - getSearchLight().setVisibility(shouldShowSearch ? View.VISIBLE : View.GONE); - final View cameraButton = getCameraButton(); - if (cameraButton != null) { - cameraButton.setVisibility( - shouldShowSearch && !mCameraDisabledByDpm ? View.VISIBLE : View.GONE); + final boolean showSearch = disableHome && !disableSearch; + final boolean showCamera = showSearch && !mCameraDisabledByDpm; + setVisibleOrGone(getSearchLight(), showSearch); + setVisibleOrGone(getCameraButton(), showCamera); + + mBarTransitions.applyBackButtonQuiescentAlpha(mBarTransitions.getMode(), true /*animate*/); + } + + private void setVisibleOrGone(View view, boolean visible) { + if (view != null) { + view.setVisibility(visible ? VISIBLE : GONE); } } @@ -574,28 +622,31 @@ public class NavigationBarView extends LinearLayout { mVertical ? "true" : "false", mShowMenu ? "true" : "false")); - final View back = getBackButton(); - final View home = getHomeButton(); - final View recent = getRecentsButton(); - final View menu = getMenuButton(); - - pw.println(" back: " - + PhoneStatusBar.viewInfo(back) - + " " + visibilityToString(back.getVisibility()) - ); - pw.println(" home: " - + PhoneStatusBar.viewInfo(home) - + " " + visibilityToString(home.getVisibility()) - ); - pw.println(" rcnt: " - + PhoneStatusBar.viewInfo(recent) - + " " + visibilityToString(recent.getVisibility()) - ); - pw.println(" menu: " - + PhoneStatusBar.viewInfo(menu) - + " " + visibilityToString(menu.getVisibility()) - ); + dumpButton(pw, "back", getBackButton()); + dumpButton(pw, "home", getHomeButton()); + dumpButton(pw, "rcnt", getRecentsButton()); + dumpButton(pw, "menu", getMenuButton()); + dumpButton(pw, "srch", getSearchLight()); + dumpButton(pw, "cmra", getCameraButton()); + pw.println(" }"); } + private static void dumpButton(PrintWriter pw, String caption, View button) { + pw.print(" " + caption + ": "); + if (button == null) { + pw.print("null"); + } else { + pw.print(PhoneStatusBar.viewInfo(button) + + " " + visibilityToString(button.getVisibility()) + + " alpha=" + button.getAlpha() + ); + if (button instanceof KeyButtonView) { + pw.print(" drawingAlpha=" + ((KeyButtonView)button).getDrawingAlpha()); + pw.print(" quiescentAlpha=" + ((KeyButtonView)button).getQuiescentAlpha()); + } + } + pw.println(); + } + } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 39a9ba7..607ce41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -53,6 +53,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -632,6 +633,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } } + PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mBroadcastReceiver.onReceive(mContext, + new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); + // receive broadcasts IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); @@ -649,14 +654,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { @Override protected void onShowSearchPanel() { if (mNavigationBarView != null) { - mNavigationBarView.transitionCameraAndSearchButtonAlpha(0.0f); + mNavigationBarView.getBarTransitions().setContentVisible(false); } } @Override protected void onHideSearchPanel() { if (mNavigationBarView != null) { - mNavigationBarView.transitionCameraAndSearchButtonAlpha(1.0f); + mNavigationBarView.getBarTransitions().setContentVisible(true); } } @@ -802,7 +807,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } private void repositionNavigationBar() { - if (mNavigationBarView == null) return; + if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return; prepareNavigationBarView(); @@ -1807,8 +1812,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { return mGestureRec; } - @Override // CommandQueue - public void setNavigationIconHints(int hints) { + private void setNavigationIconHints(int hints) { if (hints == mNavigationIconHints) return; mNavigationIconHints = hints; @@ -2045,7 +2049,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || ((vis & InputMethodService.IME_VISIBLE) != 0); - mCommandQueue.setNavigationIconHints( + setNavigationIconHints( altBack ? (mNavigationIconHints | NAVIGATION_HINT_BACK_ALT) : (mNavigationIconHints & ~NAVIGATION_HINT_BACK_ALT)); if (mQS != null) mQS.setImeWindowStatus(vis > 0); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java index 37504fb..2eef2b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java @@ -314,11 +314,19 @@ class QuickSettings { collapsePanels(); final UserManager um = UserManager.get(mContext); if (um.getUsers(true).size() > 1) { - try { - WindowManagerGlobal.getWindowManagerService().lockNow(null); - } catch (RemoteException e) { - Log.e(TAG, "Couldn't show user switcher", e); - } + // Since keyguard and systemui were merged into the same process to save + // memory, they share the same Looper and graphics context. As a result, + // there's no way to allow concurrent animation while keyguard inflates. + // The workaround is to add a slight delay to allow the animation to finish. + mHandler.postDelayed(new Runnable() { + public void run() { + try { + WindowManagerGlobal.getWindowManagerService().lockNow(null); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't show user switcher", e); + } + } + }, 400); // TODO: ideally this would be tied to the collapse of the panel } else { Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent( mContext, v, ContactsContract.Profile.CONTENT_URI, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index e77b420..4901823 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -113,7 +113,7 @@ public class StatusBarWindowView extends FrameLayout handled = super.onTouchEvent(ev); } final int action = ev.getAction(); - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) { mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); } return handled; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 55fb95d..718acc3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -36,6 +36,7 @@ import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewDebug; import android.view.accessibility.AccessibilityEvent; import android.widget.ImageView; @@ -53,10 +54,13 @@ public class KeyButtonView extends ImageView { int mTouchSlop; Drawable mGlowBG; int mGlowWidth, mGlowHeight; - float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f; + float mGlowAlpha = 0f, mGlowScale = 1f; + @ViewDebug.ExportedProperty(category = "drawing") + float mDrawingAlpha = 1f; + @ViewDebug.ExportedProperty(category = "drawing") float mQuiescentAlpha = DEFAULT_QUIESCENT_ALPHA; boolean mSupportsLongpress = true; - RectF mRect = new RectF(0f,0f,0f,0f); + RectF mRect = new RectF(); AnimatorSet mPressedAnim; Animator mAnimateToQuiescent = new ObjectAnimator(); @@ -90,8 +94,8 @@ public class KeyButtonView extends ImageView { mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true); mGlowBG = a.getDrawable(R.styleable.KeyButtonView_glowBackground); + setDrawingAlpha(mQuiescentAlpha); if (mGlowBG != null) { - setDrawingAlpha(mQuiescentAlpha); mGlowWidth = mGlowBG.getIntrinsicWidth(); mGlowHeight = mGlowBG.getIntrinsicHeight(); } @@ -126,16 +130,14 @@ public class KeyButtonView extends ImageView { public void setQuiescentAlpha(float alpha, boolean animate) { mAnimateToQuiescent.cancel(); alpha = Math.min(Math.max(alpha, 0), 1); - if (alpha == mQuiescentAlpha) return; + if (alpha == mQuiescentAlpha && alpha == mDrawingAlpha) return; mQuiescentAlpha = alpha; if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha); - if (mGlowBG != null) { - if (animate) { - mAnimateToQuiescent = animateToQuiescent(); - mAnimateToQuiescent.start(); - } else { - setDrawingAlpha(mQuiescentAlpha); - } + if (mGlowBG != null && animate) { + mAnimateToQuiescent = animateToQuiescent(); + mAnimateToQuiescent.start(); + } else { + setDrawingAlpha(mQuiescentAlpha); } } @@ -143,13 +145,15 @@ public class KeyButtonView extends ImageView { return ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha); } + public float getQuiescentAlpha() { + return mQuiescentAlpha; + } + public float getDrawingAlpha() { - if (mGlowBG == null) return 0; return mDrawingAlpha; } public void setDrawingAlpha(float x) { - if (mGlowBG == null) return; // Calling setAlpha(int), which is an ImageView-specific // method that's different from setAlpha(float). This sets // the alpha on this ImageView's drawable directly diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index a53b25a..dd13e31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -89,10 +89,6 @@ public class TvStatusBar extends BaseStatusBar { } @Override // CommandQueue - public void setNavigationIconHints(int hints) { - } - - @Override // CommandQueue public void setWindowState(int window, int state) { } diff --git a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java index e14f89a..8511de2 100644 --- a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java +++ b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java @@ -24,6 +24,9 @@ import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; import android.graphics.Rect; import android.net.Uri; import android.os.Build; @@ -53,7 +56,8 @@ class SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder { private SimpleBitmapRegionDecoderWrapper(BitmapRegionDecoder decoder) { mDecoder = decoder; } - public static SimpleBitmapRegionDecoderWrapper newInstance(String pathName, boolean isShareable) { + public static SimpleBitmapRegionDecoderWrapper newInstance( + String pathName, boolean isShareable) { try { BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(pathName, isShareable); if (d != null) { @@ -65,7 +69,8 @@ class SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder { } return null; } - public static SimpleBitmapRegionDecoderWrapper newInstance(InputStream is, boolean isShareable) { + public static SimpleBitmapRegionDecoderWrapper newInstance( + InputStream is, boolean isShareable) { try { BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(is, isShareable); if (d != null) { @@ -89,8 +94,9 @@ class SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder { } class DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder { - //byte[] streamCopy; Bitmap mBuffer; + Canvas mTempCanvas; + Paint mTempPaint; private DumbBitmapRegionDecoder(Bitmap b) { mBuffer = b; } @@ -115,9 +121,23 @@ class DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder { return mBuffer.getHeight(); } public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) { - System.out.println("DECODING WITH SAMPLE LEVEL OF " + options.inSampleSize); - return Bitmap.createBitmap( - mBuffer, wantRegion.left, wantRegion.top, wantRegion.width(), wantRegion.height()); + if (mTempCanvas == null) { + mTempCanvas = new Canvas(); + mTempPaint = new Paint(); + mTempPaint.setFilterBitmap(true); + } + int sampleSize = Math.max(options.inSampleSize, 1); + Bitmap newBitmap = Bitmap.createBitmap( + wantRegion.width() / sampleSize, + wantRegion.height() / sampleSize, + Bitmap.Config.ARGB_8888); + mTempCanvas.setBitmap(newBitmap); + mTempCanvas.save(); + mTempCanvas.scale(1f / sampleSize, 1f / sampleSize); + mTempCanvas.drawBitmap(mBuffer, -wantRegion.left, -wantRegion.top, mTempPaint); + mTempCanvas.restore(); + mTempCanvas.setBitmap(null); + return newBitmap; } } @@ -256,6 +276,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { if (regionDecoder == null) { is = regenerateInputStream(); regionDecoder = DumbBitmapRegionDecoder.newInstance(is); + Utils.closeSilently(is); } return regionDecoder; } catch (FileNotFoundException e) { @@ -280,8 +301,9 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } @Override public boolean readExif(ExifInterface ei) { + InputStream is = null; try { - InputStream is = regenerateInputStream(); + is = regenerateInputStream(); ei.readExif(is); Utils.closeSilently(is); return true; @@ -291,6 +313,8 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } catch (IOException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return false; + } finally { + Utils.closeSilently(is); } } } @@ -316,6 +340,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { if (regionDecoder == null) { is = regenerateInputStream(); regionDecoder = DumbBitmapRegionDecoder.newInstance(is); + Utils.closeSilently(is); } return regionDecoder; } diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java index d12140d..57c0581 100644 --- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java +++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java @@ -247,19 +247,19 @@ public class WallpaperCropActivity extends Activity { private static int getRotationFromExifHelper( String path, Resources res, int resId, Context context, Uri uri) { ExifInterface ei = new ExifInterface(); + InputStream is = null; + BufferedInputStream bis = null; try { if (path != null) { ei.readExif(path); } else if (uri != null) { - InputStream is = context.getContentResolver().openInputStream(uri); - BufferedInputStream bis = new BufferedInputStream(is); + is = context.getContentResolver().openInputStream(uri); + bis = new BufferedInputStream(is); ei.readExif(bis); - bis.close(); } else { - InputStream is = res.openRawResource(resId); - BufferedInputStream bis = new BufferedInputStream(is); + is = res.openRawResource(resId); + bis = new BufferedInputStream(is); ei.readExif(bis); - bis.close(); } Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); if (ori != null) { @@ -267,6 +267,9 @@ public class WallpaperCropActivity extends Activity { } } catch (IOException e) { Log.w(LOGTAG, "Getting exif data failed", e); + } finally { + Utils.closeSilently(bis); + Utils.closeSilently(is); } return 0; } @@ -326,40 +329,15 @@ public class WallpaperCropActivity extends Activity { // Get the crop boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; - Point minDims = new Point(); - Point maxDims = new Point(); + Display d = getWindowManager().getDefaultDisplay(); - d.getCurrentSizeRange(minDims, maxDims); Point displaySize = new Point(); d.getSize(displaySize); - - int maxDim = Math.max(maxDims.x, maxDims.y); - final int minDim = Math.min(minDims.x, minDims.y); - int defaultWallpaperWidth; - if (isScreenLarge(getResources())) { - defaultWallpaperWidth = (int) (maxDim * - wallpaperTravelToScreenWidthRatio(maxDim, minDim)); - } else { - defaultWallpaperWidth = Math.max((int) - (minDim * WALLPAPER_SCREENS_SPAN), maxDim); - } - boolean isPortrait = displaySize.x < displaySize.y; - int portraitHeight; - if (isPortrait) { - portraitHeight = mCropView.getHeight(); - } else { - // TODO: how to actually get the proper portrait height? - // This is not quite right: - portraitHeight = Math.max(maxDims.x, maxDims.y); - } - if (android.os.Build.VERSION.SDK_INT >= - android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { - Point realSize = new Point(); - d.getRealSize(realSize); - portraitHeight = Math.max(realSize.x, realSize.y); - } + + Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(), + getWindowManager()); // Get the crop RectF cropRect = mCropView.getCrop(); int cropRotation = mCropView.getImageRotation(); @@ -378,7 +356,7 @@ public class WallpaperCropActivity extends Activity { // (or all the way to the left, in RTL) float extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left; // Cap the amount of extra width - float maxExtraSpace = defaultWallpaperWidth / cropScale - cropRect.width(); + float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width(); extraSpace = Math.min(extraSpace, maxExtraSpace); if (ltr) { @@ -389,10 +367,10 @@ public class WallpaperCropActivity extends Activity { // ADJUST CROP HEIGHT if (isPortrait) { - cropRect.bottom = cropRect.top + portraitHeight / cropScale; + cropRect.bottom = cropRect.top + defaultWallpaperSize.y / cropScale; } else { // LANDSCAPE float extraPortraitHeight = - portraitHeight / cropScale - cropRect.height(); + defaultWallpaperSize.y / cropScale - cropRect.height(); float expandHeight = Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top), extraPortraitHeight / 2); @@ -606,13 +584,13 @@ public class WallpaperCropActivity extends Activity { } // See how much we're reducing the size of the image - int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth, - roundedTrueCrop.height() / mOutHeight); - + int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth, + roundedTrueCrop.height() / mOutHeight)); // Attempt to open a region decoder BitmapRegionDecoder decoder = null; + InputStream is = null; try { - InputStream is = regenerateInputStream(); + is = regenerateInputStream(); if (is == null) { Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString()); failure = true; @@ -622,6 +600,9 @@ public class WallpaperCropActivity extends Activity { Utils.closeSilently(is); } catch (IOException e) { Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); + } finally { + Utils.closeSilently(is); + is = null; } Bitmap crop = null; @@ -637,7 +618,7 @@ public class WallpaperCropActivity extends Activity { if (crop == null) { // BitmapRegionDecoder has failed, try to crop in-memory - InputStream is = regenerateInputStream(); + is = regenerateInputStream(); Bitmap fullSize = null; if (is != null) { BitmapFactory.Options options = new BitmapFactory.Options(); @@ -757,7 +738,7 @@ public class WallpaperCropActivity extends Activity { protected void updateWallpaperDimensions(int width, int height) { String spKey = getSharedPreferencesKey(); - SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE); + SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); SharedPreferences.Editor editor = sp.edit(); if (width != 0 && height != 0) { editor.putInt(WALLPAPER_WIDTH_KEY, width); diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java index 596435a..10bcdad 100644 --- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java +++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java @@ -117,8 +117,8 @@ public class ProxyServer extends Thread { if (!proxy.equals(Proxy.NO_PROXY)) { // Only Inets created by PacProxySelector. InetSocketAddress inetSocketAddress = - (InetSocketAddress)list.get(0).address(); - server = new Socket(inetSocketAddress.getAddress(), + (InetSocketAddress)proxy.address(); + server = new Socket(inetSocketAddress.getHostName(), inetSocketAddress.getPort()); sendLine(server, requestLine); } else { diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java index 8d97fc8..c38ad04 100644 --- a/policy/src/com/android/internal/policy/impl/BarController.java +++ b/policy/src/com/android/internal/policy/impl/BarController.java @@ -129,8 +129,8 @@ public class BarController { final boolean wasAnim = mWin.isAnimatingLw(); final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true); final int state = computeStateLw(wasVis, wasAnim, mWin, change); - updateStateLw(state); - return change; + final boolean stateChanged = updateStateLw(state); + return change || stateChanged; } private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) { @@ -139,6 +139,8 @@ public class BarController { final boolean anim = win.isAnimatingLw(); if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) { return StatusBarManager.WINDOW_STATE_HIDDEN; + } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) { + return StatusBarManager.WINDOW_STATE_SHOWING; } else if (change) { if (wasVis && vis && !wasAnim && anim) { return StatusBarManager.WINDOW_STATE_HIDING; @@ -150,7 +152,7 @@ public class BarController { return mState; } - private void updateStateLw(final int state) { + private boolean updateStateLw(final int state) { if (state != mState) { mState = state; if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state)); @@ -169,7 +171,9 @@ public class BarController { } } }); + return true; } + return false; } public boolean checkHiddenLw() { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 7c61c44..594f683 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -77,6 +77,7 @@ import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; import android.os.AsyncTask; import android.os.Binder; +import android.os.Build; import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; @@ -141,6 +142,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.URL; +import java.net.URLConnection; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -154,6 +156,10 @@ import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; + /** * @hide */ @@ -4066,8 +4072,28 @@ public class ConnectivityService extends IConnectivityManager.Stub { static class CheckMp extends AsyncTask<CheckMp.Params, Void, Integer> { private static final String CHECKMP_TAG = "CheckMp"; + + // adb shell setprop persist.checkmp.testfailures 1 to enable testing failures + private static boolean mTestingFailures; + + // Choosing 4 loops as half of them will use HTTPS and the other half HTTP + private static final int MAX_LOOPS = 4; + + // Number of milli-seconds to complete all of the retires public static final int MAX_TIMEOUT_MS = 60000; + + // The socket should retry only 5 seconds, the default is longer private static final int SOCKET_TIMEOUT_MS = 5000; + + // Sleep time for network errors + private static final int NET_ERROR_SLEEP_SEC = 3; + + // Sleep time for network route establishment + private static final int NET_ROUTE_ESTABLISHMENT_SLEEP_SEC = 3; + + // Short sleep time for polling :( + private static final int POLLING_SLEEP_SEC = 1; + private Context mContext; private ConnectivityService mCs; private TelephonyManager mTm; @@ -4093,6 +4119,31 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + // As explained to me by Brian Carlstrom and Kenny Root, Certificates can be + // issued by name or ip address, for Google its by name so when we construct + // this HostnameVerifier we'll pass the original Uri and use it to verify + // the host. If the host name in the original uril fails we'll test the + // hostname parameter just incase things change. + static class CheckMpHostnameVerifier implements HostnameVerifier { + Uri mOrgUri; + + CheckMpHostnameVerifier(Uri orgUri) { + mOrgUri = orgUri; + } + + @Override + public boolean verify(String hostname, SSLSession session) { + HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); + String orgUriHost = mOrgUri.getHost(); + boolean retVal = hv.verify(orgUriHost, session) || hv.verify(hostname, session); + if (DBG) { + log("isMobileOk: hostnameVerify retVal=" + retVal + " hostname=" + hostname + + " orgUriHost=" + orgUriHost); + } + return retVal; + } + } + /** * The call back object passed in Params. onComplete will be called * on the main thread. @@ -4103,6 +4154,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public CheckMp(Context context, ConnectivityService cs) { + if (Build.IS_DEBUGGABLE) { + mTestingFailures = + SystemProperties.getInt("persist.checkmp.testfailures", 0) == 1; + } else { + mTestingFailures = false; + } + mContext = context; mCs = cs; @@ -4174,7 +4232,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCs.setEnableFailFastMobileData(DctConstants.ENABLED); break; } - sleep(1); + sleep(POLLING_SLEEP_SEC); } } @@ -4192,7 +4250,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (VDBG) log("isMobileOk: hipri not started yet"); result = CMP_RESULT_CODE_NO_CONNECTION; - sleep(1); + sleep(POLLING_SLEEP_SEC); } // Continue trying to connect until time has run out @@ -4208,7 +4266,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } - sleep(1); + sleep(POLLING_SLEEP_SEC); result = CMP_RESULT_CODE_NO_CONNECTION; continue; } @@ -4226,7 +4284,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Get of the addresses associated with the url host. We need to use the // address otherwise HttpURLConnection object will use the name to get - // the addresses and is will try every address but that will bypass the + // the addresses and will try every address but that will bypass the // route to host we setup and the connection could succeed as the default // interface might be connected to the internet via wifi or other interface. InetAddress[] addresses; @@ -4263,14 +4321,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { int addrTried = 0; while (true) { - // Loop through at most 3 valid addresses or until + // Loop through at most MAX_LOOPS valid addresses or until // we run out of time - if (addrTried++ >= 3) { - log("too many loops tried - giving up"); + if (addrTried++ >= MAX_LOOPS) { + log("isMobileOk: too many loops tried - giving up"); break; } if (SystemClock.elapsedRealtime() >= endTime) { - log("spend too much time - giving up"); + log("isMobileOk: spend too much time - giving up"); break; } @@ -4283,25 +4341,37 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Wait a short time to be sure the route is established ?? log("isMobileOk:" + " wait to establish route to hostAddr=" + hostAddr); - sleep(3); + sleep(NET_ROUTE_ESTABLISHMENT_SLEEP_SEC); } else { log("isMobileOk:" + " could not establish route to hostAddr=" + hostAddr); + // Wait a short time before the next attempt + sleep(NET_ERROR_SLEEP_SEC); continue; } - // Rewrite the url to have numeric address to use the specific route. - // Add a pointless random query param to fool proxies into not caching. - URL newUrl = new URL(orgUri.getScheme(), - hostAddr.getHostAddress(), - orgUri.getPath() + "?q=" + rand.nextInt(Integer.MAX_VALUE)); + // Rewrite the url to have numeric address to use the specific route + // using http for half the attempts and https for the other half. + // Doing https first and http second as on a redirected walled garden + // such as t-mobile uses we get a SocketTimeoutException: "SSL + // handshake timed out" which we declare as + // CMP_RESULT_CODE_NO_TCP_CONNECTION. We could change this, but by + // having http second we will be using logic used for some time. + URL newUrl; + String scheme = (addrTried <= (MAX_LOOPS/2)) ? "https" : "http"; + newUrl = new URL(scheme, hostAddr.getHostAddress(), + orgUri.getPath()); log("isMobileOk: newUrl=" + newUrl); HttpURLConnection urlConn = null; try { - // Open the connection set the request header and get the response - urlConn = (HttpURLConnection) newUrl.openConnection( + // Open the connection set the request headers and get the response + urlConn = (HttpURLConnection)newUrl.openConnection( java.net.Proxy.NO_PROXY); + if (scheme.equals("https")) { + ((HttpsURLConnection)urlConn).setHostnameVerifier( + new CheckMpHostnameVerifier(orgUri)); + } urlConn.setInstanceFollowRedirects(false); urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConn.setReadTimeout(SOCKET_TIMEOUT_MS); @@ -4320,10 +4390,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.disconnect(); urlConn = null; + if (mTestingFailures) { + // Pretend no connection, this tests using http and https + result = CMP_RESULT_CODE_NO_CONNECTION; + log("isMobileOk: TESTING_FAILURES, pretend no connction"); + continue; + } + if (responseCode == 204) { // Return result = CMP_RESULT_CODE_CONNECTABLE; - log("isMobileOk: X expected responseCode=" + responseCode + log("isMobileOk: X got expected responseCode=" + responseCode + " result=" + result); return result; } else { @@ -4337,12 +4414,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { result = CMP_RESULT_CODE_REDIRECTED; } } catch (Exception e) { - log("isMobileOk: HttpURLConnection Exception e=" + e); + log("isMobileOk: HttpURLConnection Exception" + e); result = CMP_RESULT_CODE_NO_TCP_CONNECTION; if (urlConn != null) { urlConn.disconnect(); urlConn = null; } + sleep(NET_ERROR_SLEEP_SEC); + continue; } } log("isMobileOk: X loops|timed out result=" + result); @@ -4370,7 +4449,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("isMobileOk: connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } - sleep(1); + sleep(POLLING_SLEEP_SEC); continue; } } @@ -4435,7 +4514,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void log(String s) { + private static void log(String s) { Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s); } } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 562a50f..a996dbd 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -309,6 +309,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mShortcutInputMethodsAndSubtypes = new HashMap<InputMethodInfo, ArrayList<InputMethodSubtype>>(); + // Was the keyguard locked when this client became current? + private boolean mCurClientInKeyguard; + /** * Set to true if our ServiceConnection is currently actively bound to * a service (whether or not we have gotten its IBinder back yet). @@ -385,7 +388,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private Locale mLastSystemLocale; private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor(); private final IPackageManager mIPackageManager; - private boolean mInputBoundToKeyguard; class SettingsObserver extends ContentObserver { String mLastEnabled = ""; @@ -874,12 +876,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final boolean hardKeyShown = haveHardKeyboard && conf.hardKeyboardHidden != Configuration.HARDKEYBOARDHIDDEN_YES; - final boolean isScreenLocked = - mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); - final boolean isScreenSecurelyLocked = - isScreenLocked && mKeyguardManager.isKeyguardSecure(); - final boolean inputShown = mInputShown && (!isScreenLocked || mInputBoundToKeyguard); - final boolean inputActive = !isScreenSecurelyLocked && (inputShown || hardKeyShown); + + final boolean isScreenLocked = isKeyguardLocked(); + final boolean inputActive = !isScreenLocked && (mInputShown || hardKeyShown); // We assume the softkeyboard is shown when the input is active as long as the // hard keyboard is not shown. final boolean inputVisible = inputActive && !hardKeyShown; @@ -1135,19 +1134,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mNoBinding; } - if (mCurClient == null) { - mInputBoundToKeyguard = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); - if (DEBUG) { - Slog.v(TAG, "New bind. keyguard = " + mInputBoundToKeyguard); - } - } - if (mCurClient != cs) { + // Was the keyguard locked when switching over to the new client? + mCurClientInKeyguard = isKeyguardLocked(); // If the client is changing, we need to switch over to the new // one. unbindCurrentClientLocked(); if (DEBUG) Slog.v(TAG, "switching to client: client = " - + cs.client.asBinder()); + + cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard); // If the screen is on, inform the new client it is active if (mScreenOn) { @@ -1499,6 +1493,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + private boolean isKeyguardLocked() { + return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); + } + // Caution! This method is called in this class. Handle multi-user carefully @SuppressWarnings("deprecation") @Override @@ -1510,8 +1508,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "Ignoring setImeWindowStatus of uid " + uid + " token: " + token); return; } - synchronized (mMethodMap) { + // apply policy for binder calls + if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) { + vis = 0; + } mImeWindowVis = vis; mBackDisposition = backDisposition; if (mStatusBar != null) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 0e0f156..bb14259 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1104,6 +1104,19 @@ public class SystemServer { private static native void nativeInit(); public static void main(String[] args) { + + /* + * In case the runtime switched since last boot (such as when + * the old runtime was removed in an OTA), set the system + * property so that it is in sync. We can't do this in + * libnativehelper's JniInvocation::Init code where we already + * had to fallback to a different runtime because it is + * running as root and we need to be the system user to set + * the property. http://b/11463182 + */ + SystemProperties.set("persist.sys.dalvik.vm.lib", + VMRuntime.getRuntime().vmLibrary()); + if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { // If a device's clock is before 1970 (before 0), a lot of // APIs crash dealing with negative numbers, notably diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 6957bac..c1a60ee 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -648,6 +648,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } + // Make sure it is at least as large as the display's maximum size. + int maxSizeDimension = getMaximumSizeDimension(); + width = Math.max(width, maxSizeDimension); + height = Math.max(height, maxSizeDimension); if (width != wallpaper.width || height != wallpaper.height) { wallpaper.width = width; @@ -1146,9 +1150,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } // We always want to have some reasonable width hint. - WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); - Display d = wm.getDefaultDisplay(); - int baseSize = d.getMaximumSizeDimension(); + int baseSize = getMaximumSizeDimension(); if (wallpaper.width < baseSize) { wallpaper.width = baseSize; } @@ -1157,6 +1159,12 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } } + private int getMaximumSizeDimension() { + WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); + Display d = wm.getDefaultDisplay(); + return d.getMaximumSizeDimension(); + } + // Called by SystemBackupAgent after files are restored to disk. void settingsRestored() { // TODO: If necessary, make it work for secondary users as well. This currently assumes diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index a99b58a..43f12eb 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -76,7 +76,7 @@ class TouchExplorer implements EventStreamTransformation { private static final int STATE_DELEGATING = 0x00000004; private static final int STATE_GESTURE_DETECTING = 0x00000005; - // The minimum of the cosine between the vectors of two moving + // The maximum of the cosine between the vectors of two moving // pointers so they can be considered moving in the same direction. private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4) @@ -436,13 +436,19 @@ class TouchExplorer implements EventStreamTransformation { final int pointerIdBits = (1 << pointerId); mSendHoverEnterAndMoveDelayed.post(event, true, pointerIdBits, policyFlags); + } else { + // Cache the event until we discern exploration from gesturing. + mSendHoverEnterAndMoveDelayed.addEvent(event); } - // Cache the event until we discern exploration from gesturing. - mSendHoverEnterAndMoveDelayed.addEvent(event); } } break; case MotionEvent.ACTION_POINTER_DOWN: { - /* do nothing - let the code for ACTION_MOVE decide what to do */ + // Another finger down means that if we have not started to deliver + // hover events, we will not have to. The code for ACTION_MOVE will + // decide what we will actually do next. + mSendHoverEnterAndMoveDelayed.cancel(); + mSendHoverExitDelayed.cancel(); + mPerformLongPressDelayed.cancel(); } break; case MotionEvent.ACTION_MOVE: { final int pointerId = receivedTracker.getPrimaryPointerId(); @@ -518,14 +524,11 @@ class TouchExplorer implements EventStreamTransformation { mPerformLongPressDelayed.cancel(); } } - // The user is either double tapping or performing a long - // press, so do not send move events yet. - if (mDoubleTapDetector.firstTapDetected()) { - break; + if (mTouchExplorationInProgress) { + sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags); + sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, + policyFlags); } - sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags); - sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, - policyFlags); } } break; case 2: { @@ -539,22 +542,24 @@ class TouchExplorer implements EventStreamTransformation { mPerformLongPressDelayed.cancel(); } else { mPerformLongPressDelayed.cancel(); - // If the user is touch exploring the second pointer may be - // performing a double tap to activate an item without need - // for the user to lift his exploring finger. - // It is *important* to use the distance traveled by the pointers - // on the screen which may or may not be magnified. - final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId) - - rawEvent.getX(pointerIndex); - final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId) - - rawEvent.getY(pointerIndex); - final double moveDelta = Math.hypot(deltaX, deltaY); - if (moveDelta < mDoubleTapSlop) { - break; + if (mTouchExplorationInProgress) { + // If the user is touch exploring the second pointer may be + // performing a double tap to activate an item without need + // for the user to lift his exploring finger. + // It is *important* to use the distance traveled by the pointers + // on the screen which may or may not be magnified. + final float deltaX = receivedTracker.getReceivedPointerDownX( + pointerId) - rawEvent.getX(pointerIndex); + final float deltaY = receivedTracker.getReceivedPointerDownY( + pointerId) - rawEvent.getY(pointerIndex); + final double moveDelta = Math.hypot(deltaX, deltaY); + if (moveDelta < mDoubleTapSlop) { + break; + } + // We are sending events so send exit and gesture + // end since we transition to another state. + sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); } - // We are sending events so send exit and gesture - // end since we transition to another state. - sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); } // We know that a new state transition is to happen and the @@ -736,20 +741,34 @@ class TouchExplorer implements EventStreamTransformation { + "there is at least one pointer down!"); } case MotionEvent.ACTION_UP: { - mAms.onTouchInteractionEnd(); + // Offset the event if we are doing a long press as the + // target is not necessarily under the user's finger. + if (mLongPressingPointerId >= 0) { + event = offsetEvent(event, - mLongPressingPointerDeltaX, + - mLongPressingPointerDeltaY); + // Clear the long press state. + mLongPressingPointerId = -1; + mLongPressingPointerDeltaX = 0; + mLongPressingPointerDeltaY = 0; + } + + // Deliver the event. + sendMotionEvent(event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags); + // Announce the end of a the touch interaction. + mAms.onTouchInteractionEnd(); sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); - mLongPressingPointerId = -1; - mLongPressingPointerDeltaX = 0; - mLongPressingPointerDeltaY = 0; + mCurrentState = STATE_TOUCH_EXPLORING; } break; case MotionEvent.ACTION_CANCEL: { clear(event, policyFlags); } break; + default: { + // Deliver the event. + sendMotionEvent(event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags); + } } - // Deliver the event. - sendMotionEvent(event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags); } private void handleMotionEventGestureDetecting(MotionEvent event, int policyFlags) { @@ -959,27 +978,8 @@ class TouchExplorer implements EventStreamTransformation { // long press it, or even worse to avoid the user long pressing // on the wrong item since click and long press behave differently. if (mLongPressingPointerId >= 0) { - final int remappedIndex = event.findPointerIndex(mLongPressingPointerId); - final int pointerCount = event.getPointerCount(); - PointerProperties[] props = PointerProperties.createArray(pointerCount); - PointerCoords[] coords = PointerCoords.createArray(pointerCount); - for (int i = 0; i < pointerCount; i++) { - event.getPointerProperties(i, props[i]); - event.getPointerCoords(i, coords[i]); - if (i == remappedIndex) { - coords[i].x -= mLongPressingPointerDeltaX; - coords[i].y -= mLongPressingPointerDeltaY; - } - } - MotionEvent remapped = MotionEvent.obtain(event.getDownTime(), - event.getEventTime(), event.getAction(), event.getPointerCount(), - props, coords, event.getMetaState(), event.getButtonState(), - 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(), - event.getSource(), event.getFlags()); - if (event != prototype) { - event.recycle(); - } - event = remapped; + event = offsetEvent(event, - mLongPressingPointerDeltaX, + - mLongPressingPointerDeltaY); } if (DEBUG) { @@ -1004,6 +1004,39 @@ class TouchExplorer implements EventStreamTransformation { } /** + * Offsets all pointers in the given event by adding the specified X and Y + * offsets. + * + * @param event The event to offset. + * @param offsetX The X offset. + * @param offsetY The Y offset. + * @return An event with the offset pointers or the original event if both + * offsets are zero. + */ + private MotionEvent offsetEvent(MotionEvent event, int offsetX, int offsetY) { + if (offsetX == 0 && offsetY == 0) { + return event; + } + final int remappedIndex = event.findPointerIndex(mLongPressingPointerId); + final int pointerCount = event.getPointerCount(); + PointerProperties[] props = PointerProperties.createArray(pointerCount); + PointerCoords[] coords = PointerCoords.createArray(pointerCount); + for (int i = 0; i < pointerCount; i++) { + event.getPointerProperties(i, props[i]); + event.getPointerCoords(i, coords[i]); + if (i == remappedIndex) { + coords[i].x += offsetX; + coords[i].y += offsetY; + } + } + return MotionEvent.obtain(event.getDownTime(), + event.getEventTime(), event.getAction(), event.getPointerCount(), + props, coords, event.getMetaState(), event.getButtonState(), + 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(), + event.getSource(), event.getFlags()); + } + + /** * Computes the action for an injected event based on a masked action * and a pointer index. * @@ -1674,7 +1707,6 @@ class TouchExplorer implements EventStreamTransformation { // Keep track of the last up pointer data. private long mLastReceivedUpPointerDownTime; - private int mLastReceivedUpPointerId; private float mLastReceivedUpPointerDownX; private float mLastReceivedUpPointerDownY; @@ -1690,7 +1722,6 @@ class TouchExplorer implements EventStreamTransformation { mReceivedPointersDown = 0; mPrimaryPointerId = 0; mLastReceivedUpPointerDownTime = 0; - mLastReceivedUpPointerId = 0; mLastReceivedUpPointerDownX = 0; mLastReceivedUpPointerDownY = 0; } @@ -1823,7 +1854,6 @@ class TouchExplorer implements EventStreamTransformation { final int pointerId = event.getPointerId(pointerIndex); final int pointerFlag = (1 << pointerId); - mLastReceivedUpPointerId = 0; mLastReceivedUpPointerDownTime = 0; mLastReceivedUpPointerDownX = 0; mLastReceivedUpPointerDownX = 0; @@ -1848,7 +1878,6 @@ class TouchExplorer implements EventStreamTransformation { final int pointerId = event.getPointerId(pointerIndex); final int pointerFlag = (1 << pointerId); - mLastReceivedUpPointerId = pointerId; mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId); mLastReceivedUpPointerDownX = mReceivedPointerDownX[pointerId]; mLastReceivedUpPointerDownY = mReceivedPointerDownY[pointerId]; diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index a64940c..ea0b978a 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -26,6 +26,7 @@ import java.util.List; import android.os.Handler; import android.os.Looper; +import android.os.SystemProperties; import android.util.ArrayMap; import com.android.internal.app.ProcessStats; import com.android.internal.os.BatteryStatsImpl; @@ -76,7 +77,7 @@ public final class ActiveServices { // How long a service needs to be running until restarting its process // is no longer considered to be a relaunch of the service. - static final int SERVICE_RESTART_DURATION = 5*1000; + static final int SERVICE_RESTART_DURATION = 1*1000; // How long a service needs to be running until it will start back at // SERVICE_RESTART_DURATION after being killed. @@ -239,7 +240,12 @@ public final class ActiveServices { public ActiveServices(ActivityManagerService service) { mAm = service; - mMaxStartingBackground = ActivityManager.isLowRamDeviceStatic() ? 1 : 3; + int maxBg = 0; + try { + maxBg = Integer.parseInt(SystemProperties.get("ro.config.max_starting_bg", "0")); + } catch(RuntimeException e) { + } + mMaxStartingBackground = maxBg > 0 ? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 3; } ServiceRecord getServiceByName(ComponentName name, int callingUser) { @@ -301,7 +307,7 @@ public final class ActiveServices { ServiceRecord r = res.record; NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked( callingUid, r.packageName, service, service.getFlags(), null); - if (unscheduleServiceRestartLocked(r)) { + if (unscheduleServiceRestartLocked(r, callingUid)) { if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r); } r.lastActivity = SystemClock.uptimeMillis(); @@ -564,7 +570,7 @@ public final class ActiveServices { if (r.isForeground) { r.isForeground = false; if (r.app != null) { - mAm.updateLruProcessLocked(r.app, false, false); + mAm.updateLruProcessLocked(r.app, false, null); updateServiceForegroundLocked(r.app, true); } } @@ -597,6 +603,42 @@ public final class ActiveServices { } } + private boolean updateServiceClientActivitiesLocked(ProcessRecord proc, + ConnectionRecord modCr) { + if (modCr != null && modCr.binding.client != null) { + if (modCr.binding.client.activities.size() <= 0) { + // This connection is from a client without activities, so adding + // and removing is not interesting. + return false; + } + } + + boolean anyClientActivities = false; + for (int i=proc.services.size()-1; i>=0 && !anyClientActivities; i--) { + ServiceRecord sr = proc.services.valueAt(i); + for (int conni=sr.connections.size()-1; conni>=0 && !anyClientActivities; conni--) { + ArrayList<ConnectionRecord> clist = sr.connections.valueAt(conni); + for (int cri=clist.size()-1; cri>=0; cri--) { + ConnectionRecord cr = clist.get(cri); + if (cr.binding.client == null || cr.binding.client == proc) { + // Binding to ourself is not interesting. + continue; + } + if (cr.binding.client.activities.size() > 0) { + anyClientActivities = true; + break; + } + } + } + } + if (anyClientActivities != proc.hasClientActivities) { + proc.hasClientActivities = anyClientActivities; + mAm.updateLruProcessLocked(proc, anyClientActivities, null); + return true; + } + return false; + } + int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { @@ -659,7 +701,7 @@ public final class ActiveServices { final long origId = Binder.clearCallingIdentity(); try { - if (unscheduleServiceRestartLocked(s)) { + if (unscheduleServiceRestartLocked(s, callerApp.info.uid)) { if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: " + s); } @@ -698,6 +740,9 @@ public final class ActiveServices { if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) { b.client.hasAboveClient = true; } + if (s.app != null) { + updateServiceClientActivitiesLocked(s.app, c); + } clist = mServiceConnections.get(binder); if (clist == null) { clist = new ArrayList<ConnectionRecord>(); @@ -714,6 +759,7 @@ public final class ActiveServices { if (s.app != null) { // This could have made the service more important. + mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client); mAm.updateOomAdjLocked(s.app); } @@ -1101,16 +1147,9 @@ public final class ActiveServices { r.restartCount = 1; r.restartDelay = minDuration; } else { - if ((r.serviceInfo.applicationInfo.flags - &ApplicationInfo.FLAG_PERSISTENT) != 0) { - // Services in peristent processes will restart much more - // quickly, since they are pretty important. (Think SystemUI). - r.restartDelay += minDuration/2; - } else { - r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR; - if (r.restartDelay < minDuration) { - r.restartDelay = minDuration; - } + r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR; + if (r.restartDelay < minDuration) { + r.restartDelay = minDuration; } } } @@ -1137,7 +1176,7 @@ public final class ActiveServices { } while (repeat); } else { - // Persistent processes are immediately restrted, so there is no + // Persistent processes are immediately restarted, so there is no // reason to hold of on restarting their services. r.totalRestartCount++; r.restartCount = 0; @@ -1170,12 +1209,17 @@ public final class ActiveServices { bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true); } - private final boolean unscheduleServiceRestartLocked(ServiceRecord r) { + private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid) { if (r.restartDelay == 0) { return false; } - r.resetRestartCounter(); - mRestartingServices.remove(r); + // Remove from the restarting list; if the service is currently on the + // restarting list, or the call is coming from another app, then this + // service has become of much more interest so we reset the restart interval. + boolean removed = mRestartingServices.remove(r); + if (removed || callingUid != r.appInfo.uid) { + r.resetRestartCounter(); + } mAm.mHandler.removeCallbacks(r.restarter); return true; } @@ -1316,7 +1360,8 @@ public final class ActiveServices { app.services.add(r); bumpServiceExecutingLocked(r, execInFg, "create"); - mAm.updateLruProcessLocked(app, true, false); + mAm.updateLruProcessLocked(app, false, null); + mAm.updateOomAdjLocked(); boolean created = false; try { @@ -1508,7 +1553,7 @@ public final class ActiveServices { smap.mServicesByName.remove(r.name); smap.mServicesByIntent.remove(r.intent); r.totalRestartCount = 0; - unscheduleServiceRestartLocked(r); + unscheduleServiceRestartLocked(r, 0); // Also make sure it is not on the pending list. int N = mPendingServices.size(); @@ -1601,6 +1646,9 @@ public final class ActiveServices { if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) { b.client.updateHasAboveClientLocked(); } + if (s.app != null) { + updateServiceClientActivitiesLocked(s.app, c); + } } clist = mServiceConnections.get(binder); if (clist != null) { @@ -1621,6 +1669,13 @@ public final class ActiveServices { && b.intent.hasBound) { try { bumpServiceExecutingLocked(s, false, "unbind"); + if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0 + && s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) { + // If this service's process is not already in the cached list, + // then update it in the LRU list here because this may be causing + // it to go down there and we want it to start out near the top. + mAm.updateLruProcessLocked(s.app, false, null); + } mAm.updateOomAdjLocked(s.app); b.intent.hasBound = false; // Assume the client doesn't want to know about a rebind; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d75fe5e..164e7b7 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -34,7 +34,6 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; import com.android.internal.app.ProcessStats; -import com.android.internal.app.ResolverActivity; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.ProcessCpuTracker; @@ -218,6 +217,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_IMMERSIVE = localLOGV || false; static final boolean DEBUG_MU = localLOGV || false; static final boolean DEBUG_OOM_ADJ = localLOGV || false; + static final boolean DEBUG_LRU = localLOGV || false; static final boolean DEBUG_PAUSE = localLOGV || false; static final boolean DEBUG_POWER = localLOGV || false; static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false; @@ -457,6 +457,23 @@ public final class ActivityManagerService extends ActivityManagerNative final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>(); /** + * Information about a process that is currently marked as bad. + */ + static final class BadProcessInfo { + BadProcessInfo(long time, String shortMsg, String longMsg, String stack) { + this.time = time; + this.shortMsg = shortMsg; + this.longMsg = longMsg; + this.stack = stack; + } + + final long time; + final String shortMsg; + final String longMsg; + final String stack; + } + + /** * Set of applications that we consider to be bad, and will reject * incoming broadcasts from (which the user has no control over). * Processes are added to this set when they have crashed twice within @@ -464,7 +481,7 @@ public final class ActivityManagerService extends ActivityManagerNative * later restarted (hopefully due to some user action). The value is the * time it was added to the list. */ - final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>(); + final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<BadProcessInfo>(); /** * All of the processes we currently have running organized by pid. @@ -1743,7 +1760,8 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (mSelf.mPidsSelfLocked) { mSelf.mPidsSelfLocked.put(app.pid, app); } - mSelf.updateLruProcessLocked(app, true, false); + mSelf.updateLruProcessLocked(app, false, null); + mSelf.updateOomAdjLocked(); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( @@ -2269,7 +2287,7 @@ public final class ActivityManagerService extends ActivityManagerNative int lrui = mLruProcesses.lastIndexOf(app); if (lrui < 0) { - Log.wtf(TAG, "Adding dependent process " + app + " not on LRU list: " + Slog.wtf(TAG, "Adding dependent process " + app + " not on LRU list: " + what + " " + obj + " from " + srcApp); return index; } @@ -2289,6 +2307,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (index > 0) { index--; } + if (DEBUG_LRU) Slog.d(TAG, "Moving dep from " + lrui + " to " + index + + " in LRU list: " + app); mLruProcesses.add(index, app); return index; } @@ -2306,8 +2326,9 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj, boolean activityChange) { - final boolean hasActivity = app.activities.size() > 0; + final void updateLruProcessLocked(ProcessRecord app, boolean activityChange, + ProcessRecord client) { + final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities; final boolean hasService = false; // not impl yet. app.services.size() > 0; if (!activityChange && hasActivity) { // The process has activties, so we are only going to allow activity-based @@ -2321,8 +2342,65 @@ public final class ActivityManagerService extends ActivityManagerNative final long now = SystemClock.uptimeMillis(); app.lastActivityTime = now; + // First a quick reject: if the app is already at the position we will + // put it, then there is nothing to do. + if (hasActivity) { + final int N = mLruProcesses.size(); + if (N > 0 && mLruProcesses.get(N-1) == app) { + if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top activity: " + app); + return; + } + } else { + if (mLruProcessServiceStart > 0 + && mLruProcesses.get(mLruProcessServiceStart-1) == app) { + if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top other: " + app); + return; + } + } + int lrui = mLruProcesses.lastIndexOf(app); + if (app.persistent && lrui >= 0) { + // We don't care about the position of persistent processes, as long as + // they are in the list. + if (DEBUG_LRU) Slog.d(TAG, "Not moving, persistent: " + app); + return; + } + + /* In progress: compute new position first, so we can avoid doing work + if the process is not actually going to move. Not yet working. + int addIndex; + int nextIndex; + boolean inActivity = false, inService = false; + if (hasActivity) { + // Process has activities, put it at the very tipsy-top. + addIndex = mLruProcesses.size(); + nextIndex = mLruProcessServiceStart; + inActivity = true; + } else if (hasService) { + // Process has services, put it at the top of the service list. + addIndex = mLruProcessActivityStart; + nextIndex = mLruProcessServiceStart; + inActivity = true; + inService = true; + } else { + // Process not otherwise of interest, it goes to the top of the non-service area. + addIndex = mLruProcessServiceStart; + if (client != null) { + int clientIndex = mLruProcesses.lastIndexOf(client); + if (clientIndex < 0) Slog.d(TAG, "Unknown client " + client + " when updating " + + app); + if (clientIndex >= 0 && addIndex > clientIndex) { + addIndex = clientIndex; + } + } + nextIndex = addIndex > 0 ? addIndex-1 : addIndex; + } + + Slog.d(TAG, "Update LRU at " + lrui + " to " + addIndex + " (act=" + + mLruProcessActivityStart + "): " + app); + */ + if (lrui >= 0) { if (lrui < mLruProcessActivityStart) { mLruProcessActivityStart--; @@ -2330,23 +2408,91 @@ public final class ActivityManagerService extends ActivityManagerNative if (lrui < mLruProcessServiceStart) { mLruProcessServiceStart--; } + /* + if (addIndex > lrui) { + addIndex--; + } + if (nextIndex > lrui) { + nextIndex--; + } + */ mLruProcesses.remove(lrui); } + /* + mLruProcesses.add(addIndex, app); + if (inActivity) { + mLruProcessActivityStart++; + } + if (inService) { + mLruProcessActivityStart++; + } + */ + int nextIndex; if (hasActivity) { - // Process has activities, put it at the very tipsy-top. - mLruProcesses.add(app); - nextIndex = mLruProcessActivityStart; + final int N = mLruProcesses.size(); + if (app.activities.size() == 0 && mLruProcessActivityStart < (N-1)) { + // Process doesn't have activities, but has clients with + // activities... move it up, but one below the top (the top + // should always have a real activity). + if (DEBUG_LRU) Slog.d(TAG, "Adding to second-top of LRU activity list: " + app); + mLruProcesses.add(N-1, app); + // To keep it from spamming the LRU list (by making a bunch of clients), + // we will push down any other entries owned by the app. + final int uid = app.info.uid; + for (int i=N-2; i>mLruProcessActivityStart; i--) { + ProcessRecord subProc = mLruProcesses.get(i); + if (subProc.info.uid == uid) { + // We want to push this one down the list. If the process after + // it is for the same uid, however, don't do so, because we don't + // want them internally to be re-ordered. + if (mLruProcesses.get(i-1).info.uid != uid) { + if (DEBUG_LRU) Slog.d(TAG, "Pushing uid " + uid + " swapping at " + i + + ": " + mLruProcesses.get(i) + " : " + mLruProcesses.get(i-1)); + ProcessRecord tmp = mLruProcesses.get(i); + mLruProcesses.set(i, mLruProcesses.get(i-1)); + mLruProcesses.set(i-1, tmp); + i--; + } + } else { + // A gap, we can stop here. + break; + } + } + } else { + // Process has activities, put it at the very tipsy-top. + if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU activity list: " + app); + mLruProcesses.add(app); + } + nextIndex = mLruProcessServiceStart; } else if (hasService) { // Process has services, put it at the top of the service list. + if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU service list: " + app); mLruProcesses.add(mLruProcessActivityStart, app); nextIndex = mLruProcessServiceStart; mLruProcessActivityStart++; } else { // Process not otherwise of interest, it goes to the top of the non-service area. - mLruProcesses.add(mLruProcessServiceStart, app); - nextIndex = mLruProcessServiceStart-1; + int index = mLruProcessServiceStart; + if (client != null) { + // If there is a client, don't allow the process to be moved up higher + // in the list than that client. + int clientIndex = mLruProcesses.lastIndexOf(client); + if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG, "Unknown client " + client + + " when updating " + app); + if (clientIndex <= lrui) { + // Don't allow the client index restriction to push it down farther in the + // list than it already is. + clientIndex = lrui; + } + if (clientIndex >= 0 && index > clientIndex) { + index = clientIndex; + } + } + if (DEBUG_LRU) Slog.d(TAG, "Adding at " + index + " of LRU list: " + app); + mLruProcesses.add(index, app); + nextIndex = index-1; mLruProcessActivityStart++; mLruProcessServiceStart++; } @@ -2357,23 +2503,19 @@ public final class ActivityManagerService extends ActivityManagerNative ConnectionRecord cr = app.connections.valueAt(j); if (cr.binding != null && !cr.serviceDead && cr.binding.service != null && cr.binding.service.app != null - && cr.binding.service.app.lruSeq != mLruSeq) { + && cr.binding.service.app.lruSeq != mLruSeq + && !cr.binding.service.app.persistent) { nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex, "service connection", cr, app); } } for (int j=app.conProviders.size()-1; j>=0; j--) { ContentProviderRecord cpr = app.conProviders.get(j).provider; - if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) { + if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) { nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex, "provider reference", cpr, app); } } - - //Slog.i(TAG, "Putting proc to front: " + app.processName); - if (oomAdj) { - updateOomAdjLocked(); - } } final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) { @@ -4831,7 +4973,7 @@ public final class ActivityManagerService extends ActivityManagerNative isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(mConfiguration), app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); - updateLruProcessLocked(app, false, false); + updateLruProcessLocked(app, false, null); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); } catch (Exception e) { // todo: Yikes! What should we do? For now we will try to @@ -7419,7 +7561,7 @@ public final class ActivityManagerService extends ActivityManagerNative // make sure to count it as being accessed and thus // back up on the LRU list. This is good because // content providers are often expensive to start. - updateLruProcessLocked(cpr.proc, false, false); + updateLruProcessLocked(cpr.proc, false, null); } } @@ -8028,7 +8170,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (isolated) { mIsolatedProcesses.put(app.uid, app); } - updateLruProcessLocked(app, true, false); + updateLruProcessLocked(app, false, null); + updateOomAdjLocked(); } // This package really, really can not be stopped. @@ -9292,7 +9435,7 @@ public final class ActivityManagerService extends ActivityManagerNative ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace); startAppProblemLocked(app); app.stopFreezingAllLocked(); - return handleAppCrashLocked(app); + return handleAppCrashLocked(app, shortMsg, longMsg, stackTrace); } private void makeAppNotRespondingLocked(ProcessRecord app, @@ -9347,13 +9490,14 @@ public final class ActivityManagerService extends ActivityManagerNative app.waitDialog = null; } if (app.pid > 0 && app.pid != MY_PID) { - handleAppCrashLocked(app); + handleAppCrashLocked(app, null, null, null); killUnneededProcessLocked(app, "user request after error"); } } } - private boolean handleAppCrashLocked(ProcessRecord app) { + private boolean handleAppCrashLocked(ProcessRecord app, String shortMsg, String longMsg, + String stackTrace) { if (mHeadless) { Log.e(TAG, "handleAppCrashLocked: " + app.processName); return false; @@ -9383,7 +9527,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (!app.isolated) { // XXX We don't have a way to mark isolated processes // as bad, since they don't have a peristent identity. - mBadProcesses.put(app.info.processName, app.uid, now); + mBadProcesses.put(app.info.processName, app.uid, + new BadProcessInfo(now, shortMsg, longMsg, stackTrace)); mProcessCrashTimes.remove(app.info.processName, app.uid); } app.bad = true; @@ -10101,7 +10246,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.persistent) { outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT; } - if (app.hasActivities) { + if (app.activities.size() > 0) { outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES; } outInfo.lastTrimLevel = app.trimMemoryLevel; @@ -10645,11 +10790,11 @@ public final class ActivityManagerService extends ActivityManagerNative if (mBadProcesses.getMap().size() > 0) { boolean printed = false; - final ArrayMap<String, SparseArray<Long>> pmap = mBadProcesses.getMap(); + final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap(); final int NP = pmap.size(); for (int ip=0; ip<NP; ip++) { String pname = pmap.keyAt(ip); - SparseArray<Long> uids = pmap.valueAt(ip); + SparseArray<BadProcessInfo> uids = pmap.valueAt(ip); final int N = uids.size(); for (int i=0; i<N; i++) { int puid = uids.keyAt(i); @@ -10664,10 +10809,33 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" Bad processes:"); printedAnything = true; } + BadProcessInfo info = uids.valueAt(i); pw.print(" Bad process "); pw.print(pname); pw.print(" uid "); pw.print(puid); - pw.print(": crashed at time "); - pw.println(uids.valueAt(i)); + pw.print(": crashed at time "); pw.println(info.time); + if (info.shortMsg != null) { + pw.print(" Short msg: "); pw.println(info.shortMsg); + } + if (info.longMsg != null) { + pw.print(" Long msg: "); pw.println(info.longMsg); + } + if (info.stack != null) { + pw.println(" Stack:"); + int lastPos = 0; + for (int pos=0; pos<info.stack.length(); pos++) { + if (info.stack.charAt(pos) == '\n') { + pw.print(" "); + pw.write(info.stack, lastPos, pos-lastPos); + pw.println(); + lastPos = pos+1; + } + } + if (lastPos < info.stack.length()) { + pw.print(" "); + pw.write(info.stack, lastPos, info.stack.length()-lastPos); + pw.println(); + } + } } } } @@ -11857,7 +12025,7 @@ public final class ActivityManagerService extends ActivityManagerNative thread = r.thread; pid = r.pid; oomAdj = r.getSetAdjWithServices(); - hasActivities = r.hasActivities; + hasActivities = r.activities.size() > 0; } if (thread != null) { if (!isCheckinRequest && dumpDetails) { @@ -14079,7 +14247,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTarget = null; app.empty = false; app.cached = false; - app.hasClientActivities = false; final int activitiesSize = app.activities.size(); @@ -14089,7 +14256,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "fixed"; app.adjSeq = mAdjSeq; app.curRawAdj = app.maxAdj; - app.hasActivities = false; app.foregroundActivities = false; app.keeping = true; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; @@ -14101,16 +14267,12 @@ public final class ActivityManagerService extends ActivityManagerNative app.systemNoUi = true; if (app == TOP_APP) { app.systemNoUi = false; - app.hasActivities = true; } else if (activitiesSize > 0) { for (int j = 0; j < activitiesSize; j++) { final ActivityRecord r = app.activities.get(j); if (r.visible) { app.systemNoUi = false; } - if (r.app == app) { - app.hasActivities = true; - } } } if (!app.systemNoUi) { @@ -14121,7 +14283,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.keeping = false; app.systemNoUi = false; - app.hasActivities = false; // Determine the importance of the process, starting with most // important to least, and assign an appropriate OOM adjustment. @@ -14138,7 +14299,6 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "top-activity"; foregroundActivities = true; interesting = true; - app.hasActivities = true; procState = ActivityManager.PROCESS_STATE_TOP; } else if (app.instrumentationClass != null) { // Don't want to kill running instrumentation. @@ -14187,7 +14347,6 @@ public final class ActivityManagerService extends ActivityManagerNative + app + "?!?"); continue; } - app.hasActivities = true; if (r.visible) { // App has a visible activity; only upgrade adjustment. if (adj > ProcessList.VISIBLE_APP_ADJ) { @@ -14436,27 +14595,6 @@ public final class ActivityManagerService extends ActivityManagerNative clientAdj = adj; } } - } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) { - if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) { - // If this connection is keeping the service - // created, then we want to try to better follow - // its memory management semantics for activities. - // That is, if it is sitting in the background - // LRU list as a cached process (with activities), - // we don't want the service it is connected to - // to go into the empty LRU and quickly get killed, - // because all we'll do is just end up restarting - // the service. - if (client.hasActivities) { - if (procState > - ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT) { - procState = - ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; - app.adjType = "cch-client-act"; - } - app.hasClientActivities = true; - } - } } if (adj > clientAdj) { // If this process has recently shown UI, and @@ -14674,6 +14812,12 @@ public final class ActivityManagerService extends ActivityManagerNative } } + if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY && app.hasClientActivities) { + // This is a cached process, but with client activities. Mark it so. + procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; + app.adjType = "cch-client-act"; + } + if (adj == ProcessList.SERVICE_ADJ) { if (doingAll) { app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3); @@ -15302,7 +15446,6 @@ public final class ActivityManagerService extends ActivityManagerNative // application processes based on their current state. int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextCachedAdj = curCachedAdj+1; - int curClientCachedAdj = curCachedAdj+1; int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextEmptyAdj = curEmptyAdj+2; for (int i=N-1; i>=0; i--) { @@ -15317,11 +15460,15 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.curAdj >= ProcessList.UNKNOWN_ADJ) { switch (app.curProcState) { case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: // This process is a cached process holding activities... // assign it the next cached value for that type, and then // step that cached level. app.curRawAdj = curCachedAdj; app.curAdj = app.modifyRawOomAdj(curCachedAdj); + if (DEBUG_LRU && false) Slog.d(TAG, "Assigning activity LRU #" + i + + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj + + ")"); if (curCachedAdj != nextCachedAdj) { stepCached++; if (stepCached >= cachedFactor) { @@ -15331,25 +15478,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; } - if (curClientCachedAdj <= curCachedAdj) { - curClientCachedAdj = curCachedAdj + 1; - if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { - curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; - } - } } } break; - case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: - // Special case for cached client processes... just step - // down from after regular cached processes. - app.curRawAdj = curClientCachedAdj; - app.curAdj = app.modifyRawOomAdj(curClientCachedAdj); - curClientCachedAdj++; - if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { - curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; - } - break; default: // For everything else, assign next empty cached process // level and bump that up. Note that this means that @@ -15358,6 +15489,9 @@ public final class ActivityManagerService extends ActivityManagerNative // state is still as a service), which is what we want. app.curRawAdj = curEmptyAdj; app.curAdj = app.modifyRawOomAdj(curEmptyAdj); + if (DEBUG_LRU && false) Slog.d(TAG, "Assigning empty LRU #" + i + + " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj + + ")"); if (curEmptyAdj != nextEmptyAdj) { stepEmpty++; if (stepEmpty >= emptyFactor) { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 44ff3bc..809452c 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -61,7 +61,6 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -566,7 +565,7 @@ final class ActivityStack { // Move userId's tasks to the top. int index = mTaskHistory.size(); - for (int i = 0; i < index; ++i) { + for (int i = 0; i < index; ) { TaskRecord task = mTaskHistory.get(i); if (task.userId == userId) { if (DEBUG_TASKS) Slog.d(TAG, "switchUserLocked: stack=" + getStackId() + @@ -574,6 +573,9 @@ final class ActivityStack { mTaskHistory.remove(i); mTaskHistory.add(task); --index; + // Use same value for i. + } else { + ++i; } } if (VALIDATE_TOKENS) { @@ -997,8 +999,8 @@ final class ActivityStack { if (r.isHomeActivity()) { return true; } - if (!r.finishing && r.visible && r.fullscreen) { - // Passed activity is over a visible fullscreen activity. + if (!r.finishing && r.fullscreen) { + // Passed activity is over a fullscreen activity. return false; } } @@ -1398,7 +1400,7 @@ final class ActivityStack { if (next.app != null && next.app.thread != null) { // No reason to do full oom adj update here; we'll let that // happen whenever it needs to later. - mService.updateLruProcessLocked(next.app, false, true); + mService.updateLruProcessLocked(next.app, true, null); } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; @@ -1526,8 +1528,9 @@ final class ActivityStack { mResumedActivity = next; next.task.touchActiveTime(); mService.addRecentTaskLocked(next.task); - mService.updateLruProcessLocked(next.app, true, true); + mService.updateLruProcessLocked(next.app, true, null); updateLRUListLocked(next); + mService.updateOomAdjLocked(); // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. @@ -2781,7 +2784,7 @@ final class ActivityStack { } if (r.app.activities.isEmpty()) { // No longer have activities, so update LRU list and oom adj. - mService.updateLruProcessLocked(r.app, false, false); + mService.updateLruProcessLocked(r.app, false, null); mService.updateOomAdjLocked(); } } diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index 7650a65..8251364 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -905,7 +905,8 @@ public final class ActivityStackSupervisor { if (idx < 0) { app.activities.add(r); } - mService.updateLruProcessLocked(app, true, true); + mService.updateLruProcessLocked(app, true, null); + mService.updateOomAdjLocked(); final ActivityStack stack = r.task.stack; try { diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index 5e80135..dd3d8aa 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -220,7 +220,8 @@ public final class BroadcastQueue { r.curApp = app; app.curReceiver = r; app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); - mService.updateLruProcessLocked(app, true, false); + mService.updateLruProcessLocked(app, false, null); + mService.updateOomAdjLocked(); // Tell the application to launch this receiver. r.intent.setComponent(r.curComponent); diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 486e916..187cd44 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -86,7 +86,6 @@ final class ProcessRecord { boolean keeping; // Actively running code so don't kill due to that? boolean setIsForeground; // Running foreground UI when last set? boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle? - boolean hasActivities; // Are there any activities running in this process? boolean hasClientActivities; // Are there any client services with activities? boolean hasStartedServices; // Are there any started services running in this process? boolean foregroundServices; // Running any services that are foreground? @@ -265,9 +264,8 @@ final class ProcessRecord { pw.print(prefix); pw.print("persistent="); pw.print(persistent); pw.print(" removed="); pw.println(removed); } - if (hasActivities || hasClientActivities || foregroundActivities) { - pw.print(prefix); pw.print("hasActivities="); pw.print(hasActivities); - pw.print(" hasClientActivities="); pw.print(hasClientActivities); + if (hasClientActivities || foregroundActivities) { + pw.print(prefix); pw.print("hasClientActivities="); pw.print(hasClientActivities); pw.print(" foregroundActivities="); pw.println(foregroundActivities); } if (hasStartedServices) { diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 3d6b3c9..7291dd4 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -4959,6 +4959,18 @@ public class PackageManagerService extends IPackageManager.Stub { permissionMap.put(p.info.name, bp); } if (bp.perm == null) { + if (bp.sourcePackage != null + && !bp.sourcePackage.equals(p.info.packageName)) { + // If this is a permission that was formerly defined by a non-system + // app, but is now defined by a system app (following an upgrade), + // discard the previous declaration and consider the system's to be + // canonical. + if (isSystemApp(p.owner)) { + Slog.i(TAG, "New decl " + p.owner + " of permission " + + p.info.name + " is system"); + bp.sourcePackage = null; + } + } if (bp.sourcePackage == null || bp.sourcePackage.equals(p.info.packageName)) { BasePermission tree = findPermissionTreeLP(p.info.name); diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index d3ccba6..0079b54 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -1959,10 +1959,14 @@ final class Settings { } boolean doNonData = true; + boolean hasSchemes = false; for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) { boolean doScheme = true; String scheme = tmpPa.getDataScheme(ischeme); + if (scheme != null && !scheme.isEmpty()) { + hasSchemes = true; + } for (int issp=0; issp<tmpPa.countDataSchemeSpecificParts(); issp++) { Uri.Builder builder = new Uri.Builder(); builder.scheme(scheme); @@ -2016,11 +2020,25 @@ final class Settings { } for (int idata=0; idata<tmpPa.countDataTypes(); idata++) { - Intent finalIntent = new Intent(intent); String mimeType = tmpPa.getDataType(idata); - finalIntent.setType(mimeType); - applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, - null, null, null, null, mimeType, userId); + if (hasSchemes) { + Uri.Builder builder = new Uri.Builder(); + for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) { + String scheme = tmpPa.getDataScheme(ischeme); + if (scheme != null && !scheme.isEmpty()) { + Intent finalIntent = new Intent(intent); + builder.scheme(scheme); + finalIntent.setDataAndType(builder.build(), mimeType); + applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + scheme, null, null, null, mimeType, userId); + } + } + } else { + Intent finalIntent = new Intent(intent); + finalIntent.setType(mimeType); + applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn, + null, null, null, null, mimeType, userId); + } doNonData = false; } diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java index 976a328..60d44c7 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/java/com/android/server/power/DisplayPowerController.java @@ -298,6 +298,10 @@ final class DisplayPowerController { // True if mAmbientLux holds a valid value. private boolean mAmbientLuxValid; + // The ambient light level threshold at which to brighten or darken the screen. + private float mBrighteningLuxThreshold; + private float mDarkeningLuxThreshold; + // The most recent light sample. private float mLastObservedLux; @@ -945,12 +949,24 @@ final class DisplayPowerController { mLastObservedLuxTime = time; } + private void setAmbientLux(float lux) { + mAmbientLux = lux; + mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS); + mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS); + } + private void updateAmbientLux(long time) { // If the light sensor was just turned on then immediately update our initial // estimate of the current ambient light level. - if (!mAmbientLuxValid - || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) { - mAmbientLux = mRecentShortTermAverageLux; + if (!mAmbientLuxValid) { + final long timeWhenSensorWarmedUp = + mLightSensorWarmUpTimeConfig + mLightSensorEnableTime; + if (time < timeWhenSensorWarmedUp) { + mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, + timeWhenSensorWarmedUp); + return; + } + setAmbientLux(mRecentShortTermAverageLux); mAmbientLuxValid = true; mDebounceLuxDirection = 0; mDebounceLuxTime = time; @@ -961,98 +977,90 @@ final class DisplayPowerController { + ", mAmbientLux=" + mAmbientLux); } updateAutoBrightness(true); - return; - } - - // Determine whether the ambient environment appears to be brightening. - float brighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS); - if (mRecentShortTermAverageLux > brighteningLuxThreshold - && mRecentLongTermAverageLux > brighteningLuxThreshold) { + } else if (mRecentShortTermAverageLux > mBrighteningLuxThreshold + && mRecentLongTermAverageLux > mBrighteningLuxThreshold) { + // The ambient environment appears to be brightening. if (mDebounceLuxDirection <= 0) { mDebounceLuxDirection = 1; mDebounceLuxTime = time; if (DEBUG) { Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for " + BRIGHTENING_LIGHT_DEBOUNCE + " ms: " - + "brighteningLuxThreshold=" + brighteningLuxThreshold + + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux + ", mAmbientLux=" + mAmbientLux); } } long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE; - if (time >= debounceTime) { - mAmbientLux = mRecentShortTermAverageLux; - if (DEBUG) { - Slog.d(TAG, "updateAmbientLux: Brightened: " - + "brighteningLuxThreshold=" + brighteningLuxThreshold - + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux - + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux - + ", mAmbientLux=" + mAmbientLux); - } - updateAutoBrightness(true); - } else { + if (time < debounceTime) { mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime); + return; } - return; - } - - // Determine whether the ambient environment appears to be darkening. - float darkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS); - if (mRecentShortTermAverageLux < darkeningLuxThreshold - && mRecentLongTermAverageLux < darkeningLuxThreshold) { + setAmbientLux(mRecentShortTermAverageLux); + if (DEBUG) { + Slog.d(TAG, "updateAmbientLux: Brightened: " + + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold + + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux + + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux + + ", mAmbientLux=" + mAmbientLux); + } + updateAutoBrightness(true); + } else if (mRecentShortTermAverageLux < mDarkeningLuxThreshold + && mRecentLongTermAverageLux < mDarkeningLuxThreshold) { + // The ambient environment appears to be darkening. if (mDebounceLuxDirection >= 0) { mDebounceLuxDirection = -1; mDebounceLuxTime = time; if (DEBUG) { Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for " + DARKENING_LIGHT_DEBOUNCE + " ms: " - + "darkeningLuxThreshold=" + darkeningLuxThreshold + + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux + ", mAmbientLux=" + mAmbientLux); } } long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE; - if (time >= debounceTime) { - // Be conservative about reducing the brightness, only reduce it a little bit - // at a time to avoid having to bump it up again soon. - mAmbientLux = Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux); - if (DEBUG) { - Slog.d(TAG, "updateAmbientLux: Darkened: " - + "darkeningLuxThreshold=" + darkeningLuxThreshold - + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux - + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux - + ", mAmbientLux=" + mAmbientLux); - } - updateAutoBrightness(true); - } else { + if (time < debounceTime) { mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime); + return; } - return; - } - - // No change or change is within the hysteresis thresholds. - if (mDebounceLuxDirection != 0) { + // Be conservative about reducing the brightness, only reduce it a little bit + // at a time to avoid having to bump it up again soon. + setAmbientLux(Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux)); + if (DEBUG) { + Slog.d(TAG, "updateAmbientLux: Darkened: " + + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold + + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux + + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux + + ", mAmbientLux=" + mAmbientLux); + } + updateAutoBrightness(true); + } else if (mDebounceLuxDirection != 0) { + // No change or change is within the hysteresis thresholds. mDebounceLuxDirection = 0; mDebounceLuxTime = time; if (DEBUG) { Slog.d(TAG, "updateAmbientLux: Canceled debounce: " - + "brighteningLuxThreshold=" + brighteningLuxThreshold - + ", darkeningLuxThreshold=" + darkeningLuxThreshold + + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold + + ", mDarkeningLuxThreshold=" + mDarkeningLuxThreshold + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux + ", mAmbientLux=" + mAmbientLux); } } - // If the light level does not change, then the sensor may not report - // a new value. This can cause problems for the auto-brightness algorithm - // because the filters might not be updated. To work around it, we want to - // make sure to update the filters whenever the observed light level could - // possibly exceed one of the hysteresis thresholds. - if (mLastObservedLux > brighteningLuxThreshold - || mLastObservedLux < darkeningLuxThreshold) { + // Now that we've done all of that, we haven't yet posted a debounce + // message. So consider the case where current lux is beyond the + // threshold. It's possible that the light sensor may not report values + // if the light level does not change, so we need to occasionally + // synthesize sensor readings in order to make sure the brightness is + // adjusted accordingly. Note these thresholds may have changed since + // we entered the function because we called setAmbientLux and + // updateAutoBrightness along the way. + if (mLastObservedLux > mBrighteningLuxThreshold + || mLastObservedLux < mDarkeningLuxThreshold) { mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS); } diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java index 8a3997a..98acc27 100644 --- a/services/java/com/android/server/print/PrintManagerService.java +++ b/services/java/com/android/server/print/PrintManagerService.java @@ -366,7 +366,7 @@ public final class PrintManagerService extends IPrintManager.Stub { pw.println("PRINT MANAGER STATE (dumpsys print)"); final int userStateCount = mUserStates.size(); for (int i = 0; i < userStateCount; i++) { - UserState userState = mUserStates.get(i); + UserState userState = mUserStates.valueAt(i); userState.dump(fd, pw, ""); pw.println(); } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 63e09db..e1e9f5c 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -8269,7 +8269,8 @@ public class WindowManagerService extends IWindowManager.Stub // windows, since that means "perform layout as normal, // just don't display"). if (!gone || !win.mHaveFrame || win.mLayoutNeeded - || (win.mAttrs.type == TYPE_KEYGUARD && win.isConfigChanged()) + || win.mAttrs.type == TYPE_KEYGUARD && win.isConfigChanged() + || mOpeningApps.contains(win.mAppToken) || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) { if (!win.mLayoutAttached) { if (initial) { diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index ab429fd..e3a1aa6 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -1957,6 +1957,27 @@ public class PhoneNumberUtils } /** + * Process phone number for CDMA, converting plus code using the home network number format. + * This is used for outgoing SMS messages. + * + * @param dialStr the original dial string + * @return the converted dial string + * @hide for internal use + */ + public static String cdmaCheckAndProcessPlusCodeForSms(String dialStr) { + if (!TextUtils.isEmpty(dialStr)) { + if (isReallyDialable(dialStr.charAt(0)) && isNonSeparator(dialStr)) { + String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, ""); + if (!TextUtils.isEmpty(defaultIso)) { + int format = getFormatTypeFromCountryCode(defaultIso); + return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr, format, format); + } + } + } + return dialStr; + } + + /** * This function should be called from checkAndProcessPlusCode only * And it is used for test purpose also. * |