Merge "ITelephony.aidl: Minor spelling fix." into lmp-dev
diff --git a/Android.mk b/Android.mk
index 96b2b17..a823ba0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -340,8 +340,6 @@
 	media/java/android/media/tv/ITvInputServiceCallback.aidl \
 	media/java/android/media/tv/ITvInputSession.aidl \
 	media/java/android/media/tv/ITvInputSessionCallback.aidl \
-	telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl \
-	telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl \
 	telecomm/java/com/android/internal/telecomm/ICallVideoProvider.aidl \
 	telecomm/java/com/android/internal/telecomm/ICallVideoClient.aidl \
 	telecomm/java/com/android/internal/telecomm/IConnectionService.aidl \
@@ -362,10 +360,6 @@
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
-	telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
-	telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
-	telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl \
-	telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 623c281..c841a8b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1368,6 +1368,7 @@
     field public static final int windowContentTransitions = 16843794; // 0x1010412
     field public static final int windowDisablePreview = 16843298; // 0x1010222
     field public static final int windowDrawsSystemBarBackgrounds = 16843858; // 0x1010452
+    field public static final int windowElevation = 16843922; // 0x1010492
     field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
     field public static final int windowEnterAnimation = 16842932; // 0x10100b4
     field public static final int windowEnterTransition = 16843833; // 0x1010439
@@ -3309,6 +3310,7 @@
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.LoaderManager getLoaderManager();
     method public java.lang.String getLocalClassName();
+    method public final android.media.session.MediaController getMediaController();
     method public android.view.MenuInflater getMenuInflater();
     method public final android.app.Activity getParent();
     method public android.content.Intent getParentActivityIntent();
@@ -3432,6 +3434,7 @@
     method public void setFinishOnTouchOutside(boolean);
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
+    method public final void setMediaController(android.media.session.MediaController);
     method public boolean setMediaPlaying(boolean);
     method public final void setProgress(int);
     method public final void setProgressBarIndeterminate(boolean);
@@ -3510,6 +3513,7 @@
     method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
     method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
+    method public boolean isInLockTaskMode();
     method public boolean isLowRamDevice();
     method public static boolean isRunningInTestHarness();
     method public static boolean isUserAMonkey();
@@ -7058,6 +7062,7 @@
     method public abstract java.io.File getFileStreamPath(java.lang.String);
     method public abstract java.io.File getFilesDir();
     method public abstract android.os.Looper getMainLooper();
+    method public abstract java.io.File getNoBackupFilesDir();
     method public abstract java.io.File getObbDir();
     method public abstract java.io.File[] getObbDirs();
     method public abstract java.lang.String getPackageCodePath();
@@ -7227,6 +7232,7 @@
     method public java.io.File getFileStreamPath(java.lang.String);
     method public java.io.File getFilesDir();
     method public android.os.Looper getMainLooper();
+    method public java.io.File getNoBackupFilesDir();
     method public java.io.File getObbDir();
     method public java.io.File[] getObbDirs();
     method public java.lang.String getPackageCodePath();
@@ -8367,6 +8373,9 @@
     field public java.lang.String targetPackage;
   }
 
+  public class KeySet {
+  }
+
   public class LabeledIntent extends android.content.Intent {
     ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
     ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
@@ -8504,6 +8513,7 @@
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public abstract java.lang.String getNameForUid(int);
@@ -8522,12 +8532,15 @@
     method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.KeySet getSigningKeySet(java.lang.String);
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract java.lang.String[] getSystemSharedLibraryNames();
     method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract boolean hasSystemFeature(java.lang.String);
     method public abstract boolean isSafeMode();
+    method public abstract boolean isSignedBy(java.lang.String, android.content.pm.KeySet);
+    method public abstract boolean isSignedByExactly(java.lang.String, android.content.pm.KeySet);
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
     method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
     method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
@@ -8584,12 +8597,14 @@
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
+    field public static final java.lang.String FEATURE_SENSOR_AMBIENT_TEMPERATURE = "android.hardware.sensor.ambient_temperature";
     field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
     field public static final java.lang.String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
     field public static final java.lang.String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
     field public static final java.lang.String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
     field public static final java.lang.String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
     field public static final java.lang.String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
+    field public static final java.lang.String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity";
     field public static final java.lang.String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
     field public static final java.lang.String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
     field public static final java.lang.String FEATURE_SIP = "android.software.sip";
@@ -16217,19 +16232,14 @@
   }
 
   public final class PlaybackState implements android.os.Parcelable {
-    ctor public PlaybackState();
-    ctor public PlaybackState(android.media.session.PlaybackState);
     method public int describeContents();
     method public long getActions();
     method public long getBufferPosition();
     method public java.lang.CharSequence getErrorMessage();
-    method public float getPlaybackRate();
+    method public long getLastPositionUpdateTime();
+    method public float getPlaybackSpeed();
     method public long getPosition();
     method public int getState();
-    method public void setActions(long);
-    method public void setBufferPosition(long);
-    method public void setErrorMessage(java.lang.CharSequence);
-    method public void setState(int, long, float);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
     field public static final long ACTION_PAUSE = 2L; // 0x2L
@@ -16256,6 +16266,17 @@
     field public static final int STATE_STOPPED = 1; // 0x1
   }
 
+  public static final class PlaybackState.Builder {
+    ctor public PlaybackState.Builder();
+    ctor public PlaybackState.Builder(android.media.session.PlaybackState);
+    method public android.media.session.PlaybackState build();
+    method public android.media.session.PlaybackState.Builder setActions(long);
+    method public android.media.session.PlaybackState.Builder setBufferPosition(long);
+    method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence);
+    method public android.media.session.PlaybackState.Builder setState(int, long, float, long);
+    method public android.media.session.PlaybackState.Builder setState(int, long, float);
+  }
+
 }
 
 package android.media.tv {
@@ -22936,7 +22957,7 @@
     method protected void onDisconnected();
     method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
     method protected abstract void onRequestCancelPrintJob(android.printservice.PrintJob);
-    field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.PRINTER_INFO";
+    field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
     field public static final java.lang.String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
     field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
     field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
@@ -25581,6 +25602,7 @@
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String SOURCE_DATA = "source_data";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
+    field public static final java.lang.String TRANSCRIPTION = "transcription";
   }
 
 }
@@ -27834,6 +27856,62 @@
 
 package android.telecomm {
 
+  public final class Call {
+    method public void addListener(android.telecomm.Call.Listener);
+    method public void answer();
+    method public void conference();
+    method public void disconnect();
+    method public android.telecomm.RemoteCallVideoProvider getCallVideoProvider();
+    method public java.util.List<java.lang.String> getCannedTextResponses();
+    method public java.util.List<android.telecomm.Call> getChildren();
+    method public android.telecomm.Call.Details getDetails();
+    method public android.telecomm.Call getParent();
+    method public java.lang.String getRemainingPostDialSequence();
+    method public int getState();
+    method public void hold();
+    method public void phoneAccountClicked();
+    method public void playDtmfTone(char);
+    method public void postDialContinue(boolean);
+    method public void reject(boolean, java.lang.String);
+    method public void removeListener(android.telecomm.Call.Listener);
+    method public void splitFromConference();
+    method public void stopDtmfTone();
+    method public void swapWithBackgroundCall();
+    method public void unhold();
+    field public static final int STATE_ACTIVE = 4; // 0x4
+    field public static final int STATE_DIALING = 1; // 0x1
+    field public static final int STATE_DISCONNECTED = 7; // 0x7
+    field public static final int STATE_HOLDING = 3; // 0x3
+    field public static final int STATE_NEW = 0; // 0x0
+    field public static final int STATE_RINGING = 2; // 0x2
+  }
+
+  public static class Call.Details {
+    method public android.telecomm.PhoneAccount getAccount();
+    method public java.lang.String getCallerDisplayName();
+    method public int getCallerDisplayNamePresentation();
+    method public int getCapabilities();
+    method public long getConnectTimeMillis();
+    method public int getDisconnectCauseCode();
+    method public java.lang.String getDisconnectCauseMsg();
+    method public android.telecomm.GatewayInfo getGatewayInfo();
+    method public android.net.Uri getHandle();
+    method public int getHandlePresentation();
+  }
+
+  public static abstract class Call.Listener {
+    ctor public Call.Listener();
+    method public void onCallDestroyed(android.telecomm.Call);
+    method public void onCallVideoProviderChanged(android.telecomm.Call, android.telecomm.RemoteCallVideoProvider);
+    method public void onCannedTextResponsesLoaded(android.telecomm.Call, java.util.List<java.lang.String>);
+    method public void onChildrenChanged(android.telecomm.Call, java.util.List<android.telecomm.Call>);
+    method public void onDetailsChanged(android.telecomm.Call, android.telecomm.Call.Details);
+    method public void onParentChanged(android.telecomm.Call, android.telecomm.Call);
+    method public void onPostDial(android.telecomm.Call, java.lang.String);
+    method public void onPostDialWait(android.telecomm.Call, java.lang.String);
+    method public void onStateChanged(android.telecomm.Call, int);
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -27883,35 +27961,6 @@
     field public static final int UNKNOWN = 2; // 0x2
   }
 
-  public final class CallServiceDescriptor implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.lang.String getConnectionServiceId();
-    method public int getNetworkType();
-    method public android.content.ComponentName getServiceComponent();
-    method public static android.telecomm.CallServiceDescriptor.Builder newBuilder(android.content.Context);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int FLAG_MOBILE = 4; // 0x4
-    field public static final int FLAG_PSTN = 2; // 0x2
-    field public static final int FLAG_WIFI = 1; // 0x1
-  }
-
-  public static class CallServiceDescriptor.Builder {
-    method public android.telecomm.CallServiceDescriptor build();
-    method public android.telecomm.CallServiceDescriptor.Builder setConnectionService(java.lang.Class<? extends android.telecomm.ConnectionService>);
-    method public android.telecomm.CallServiceDescriptor.Builder setNetworkType(int);
-  }
-
-  public final class CallServiceLookupResponse {
-    method public void setCallServiceDescriptors(java.util.List<android.telecomm.CallServiceDescriptor>);
-  }
-
-  public abstract class CallServiceProvider extends android.app.Service {
-    ctor protected CallServiceProvider();
-    method public abstract void lookupCallServices(android.telecomm.CallServiceLookupResponse);
-    method public android.os.IBinder onBind(android.content.Intent);
-  }
-
   public final class CallState extends java.lang.Enum {
     method public static android.telecomm.CallState valueOf(java.lang.String);
     method public static final android.telecomm.CallState[] values();
@@ -27920,8 +27969,6 @@
     enum_constant public static final android.telecomm.CallState DISCONNECTED;
     enum_constant public static final android.telecomm.CallState NEW;
     enum_constant public static final android.telecomm.CallState ON_HOLD;
-    enum_constant public static final android.telecomm.CallState POST_DIAL;
-    enum_constant public static final android.telecomm.CallState POST_DIAL_WAIT;
     enum_constant public static final android.telecomm.CallState RINGING;
   }
 
@@ -28083,7 +28130,6 @@
     method public java.util.List<java.lang.String> getCannedSmsResponses();
     method public int getCapabilities();
     method public long getConnectTimeMillis();
-    method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
     method public int getDisconnectCauseCode();
     method public java.lang.String getDisconnectCauseMsg();
     method public android.telecomm.GatewayInfo getGatewayInfo();
@@ -28096,31 +28142,52 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
-  public abstract class InCallService extends android.app.Service {
+  public abstract class InCallService {
     ctor protected InCallService();
-    method protected abstract void addCall(android.telecomm.InCallCall);
-    method protected abstract void bringToForeground(boolean);
-    method protected final android.telecomm.InCallAdapter getAdapter();
-    method protected void onAdapterAttached(android.telecomm.InCallAdapter);
-    method protected abstract void onAudioStateChanged(android.telecomm.CallAudioState);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void setPostDial(java.lang.String, java.lang.String);
-    method protected abstract void setPostDialWait(java.lang.String, java.lang.String);
-    method protected abstract void updateCall(android.telecomm.InCallCall);
+    method public final android.os.IBinder getBinder();
+    method public android.telecomm.Phone getPhone();
+    method public void onPhoneCreated(android.telecomm.Phone);
+    method public void onPhoneDestroyed(android.telecomm.Phone);
   }
 
-  public final class PhoneAccount implements android.os.Parcelable {
-    ctor public PhoneAccount(android.content.ComponentName, java.lang.String, android.net.Uri, java.lang.String, java.lang.String, boolean, boolean);
+  public final class Phone {
+    method public final void addListener(android.telecomm.Phone.Listener);
+    method public final android.telecomm.CallAudioState getAudioState();
+    method public final java.util.List<android.telecomm.Call> getCalls();
+    method public final void removeListener(android.telecomm.Phone.Listener);
+    method public final void setAudioRoute(int);
+    method public final void setMuted(boolean);
+  }
+
+  public static abstract class Phone.Listener {
+    ctor public Phone.Listener();
+    method public void onAudioStateChanged(android.telecomm.Phone, android.telecomm.CallAudioState);
+    method public void onBringToForeground(android.telecomm.Phone, boolean);
+    method public void onCallAdded(android.telecomm.Phone, android.telecomm.Call);
+    method public void onCallRemoved(android.telecomm.Phone, android.telecomm.Call);
+  }
+
+  public class PhoneAccount implements android.os.Parcelable {
+    ctor public PhoneAccount(android.content.ComponentName, java.lang.String, android.net.Uri, int);
     method public int describeContents();
+    method public int getCapabilities();
     method public android.content.ComponentName getComponentName();
     method public android.net.Uri getHandle();
-    method public android.graphics.drawable.Drawable getIcon(android.content.Context);
-    method public android.graphics.drawable.Drawable getIcon(android.content.Context, int);
     method public java.lang.String getId();
-    method public java.lang.String getLabel(android.content.Context);
-    method public java.lang.String getShortDescription(android.content.Context);
-    method public boolean isEnabled();
-    method public boolean isSystemDefault();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
+    field public static final int CAPABILITY_SIM_CALL_MANAGER = 1; // 0x1
+    field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public class PhoneAccountMetadata implements android.os.Parcelable {
+    ctor public PhoneAccountMetadata(android.telecomm.PhoneAccount, int, java.lang.String, java.lang.String);
+    method public int describeContents();
+    method public android.telecomm.PhoneAccount getAccount();
+    method public android.graphics.drawable.Drawable getIcon(android.content.Context);
+    method public java.lang.String getLabel();
+    method public java.lang.String getShortDescription();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -28135,18 +28202,17 @@
     method public void updatePeerDimensions(int, int) throws android.os.RemoteException;
   }
 
-  public class RemoteCallVideoProvider implements android.os.IBinder.DeathRecipient {
-    method public void binderDied();
-    method public void requestCallDataUsage() throws android.os.RemoteException;
-    method public void requestCameraCapabilities() throws android.os.RemoteException;
-    method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
-    method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile) throws android.os.RemoteException;
-    method public void setCallVideoClient(android.telecomm.CallVideoClient) throws android.os.RemoteException;
+  public class RemoteCallVideoProvider {
+    method public void requestCallDataUsage();
+    method public void requestCameraCapabilities();
+    method public void sendSessionModifyRequest(android.telecomm.VideoCallProfile);
+    method public void sendSessionModifyResponse(android.telecomm.VideoCallProfile);
+    method public void setCallVideoClient(android.telecomm.CallVideoClient);
     method public void setCamera(java.lang.String) throws android.os.RemoteException;
-    method public void setDeviceOrientation(int) throws android.os.RemoteException;
-    method public void setDisplaySurface(android.view.Surface) throws android.os.RemoteException;
-    method public void setPauseImage(java.lang.String) throws android.os.RemoteException;
-    method public void setPreviewSurface(android.view.Surface) throws android.os.RemoteException;
+    method public void setDeviceOrientation(int);
+    method public void setDisplaySurface(android.view.Surface);
+    method public void setPauseImage(java.lang.String);
+    method public void setPreviewSurface(android.view.Surface);
     method public void setZoom(float) throws android.os.RemoteException;
   }
 
@@ -28213,16 +28279,16 @@
 
   public final class TelecommConstants {
     ctor public TelecommConstants();
-    field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
     field public static final java.lang.String ACTION_CONNECTION_SERVICE;
+    field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.intent.action.CONNECTION_SERVICE_CONFIGURE";
     field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
-    field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
     field public static final java.lang.String EXTRA_CONNECTION_SERVICE = "android.telecomm.extra.CONNECTION_SERVICE";
     field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
+    field public static final java.lang.String EXTRA_PHONE_ACCOUNT = "android.intent.extra.PHONE_ACCOUNT";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.intent.extra.START_CALL_WITH_VIDEO_STATE";
   }
@@ -28661,7 +28727,6 @@
   }
 
   public class TelephonyManager {
-    method public java.util.List<android.telecomm.PhoneAccount> getAccounts();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
     method public android.telephony.CellLocation getCellLocation();
@@ -28710,7 +28775,6 @@
     field public static final int DATA_CONNECTING = 1; // 0x1
     field public static final int DATA_DISCONNECTED = 0; // 0x0
     field public static final int DATA_SUSPENDED = 3; // 0x3
-    field public static final java.lang.String EXTRA_ACCOUNT = "account";
     field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
     field public static final java.lang.String EXTRA_STATE = "state";
     field public static final java.lang.String EXTRA_STATE_IDLE;
@@ -29226,6 +29290,7 @@
     method public java.io.File getFileStreamPath(java.lang.String);
     method public java.io.File getFilesDir();
     method public android.os.Looper getMainLooper();
+    method public java.io.File getNoBackupFilesDir();
     method public java.io.File getObbDir();
     method public java.io.File[] getObbDirs();
     method public java.lang.String getPackageCodePath();
@@ -34276,6 +34341,7 @@
     method protected final int getForcedWindowFlags();
     method public abstract android.view.LayoutInflater getLayoutInflater();
     method protected final int getLocalFeatures();
+    method public android.media.session.MediaController getMediaController();
     method public abstract int getNavigationBarColor();
     method public android.transition.Transition getSharedElementEnterTransition();
     method public android.transition.Transition getSharedElementExitTransition();
@@ -34332,6 +34398,7 @@
     method public void setLayout(int, int);
     method public void setLocalFocus(boolean, boolean);
     method public void setLogo(int);
+    method public void setMediaController(android.media.session.MediaController);
     method public abstract void setNavigationBarColor(int);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 3d0eec4..3a2ca30 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -50,6 +50,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.content.PackageHelper;
@@ -923,33 +924,13 @@
                     return;
                 }
             } else if (opt.equals("--abi")) {
-                abi = nextOptionData();
-                if (abi == null) {
-                    System.err.println("Error: must supply argument for --abi");
-                    return;
-                }
+                abi = checkAbiArgument(nextOptionData());
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
             }
         }
 
-        if (abi != null) {
-            final String[] supportedAbis = Build.SUPPORTED_ABIS;
-            boolean matched = false;
-            for (String supportedAbi : supportedAbis) {
-                if (supportedAbi.equals(abi)) {
-                    matched = true;
-                    break;
-                }
-            }
-
-            if (!matched) {
-                System.err.println("Error: abi " + abi + " not supported on this device.");
-                return;
-            }
-        }
-
         final Uri verificationURI;
         final Uri originatingURI;
         final Uri referrerURI;
@@ -1044,6 +1025,8 @@
             } else if (opt.equals("-S")) {
                 params.deltaSize = Long.parseLong(nextOptionData());
                 params.progressMax = (int) params.deltaSize;
+            } else if (opt.equals("--abi")) {
+                params.abiOverride = checkAbiArgument(nextOptionData());
             } else {
                 throw new IllegalArgumentException("Unknown option " + opt);
             }
@@ -1684,6 +1667,21 @@
         }
     }
 
+    private static String checkAbiArgument(String abi) {
+        if (TextUtils.isEmpty(abi)) {
+            throw new IllegalArgumentException("Missing ABI argument");
+        }
+
+        final String[] supportedAbis = Build.SUPPORTED_ABIS;
+        for (String supportedAbi : supportedAbis) {
+            if (supportedAbi.equals(abi)) {
+                return abi;
+            }
+        }
+
+        throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
+    }
+
     private String nextOption() {
         if (mNextArg >= mArgs.length) {
             return null;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d20a5dc..cac646d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -23,6 +23,7 @@
 import android.util.ArrayMap;
 import android.util.SuperNotCalledException;
 import android.widget.Toolbar;
+
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.WindowDecorActionBar;
 import com.android.internal.app.ToolbarActionBar;
@@ -51,6 +52,8 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -109,14 +112,14 @@
  * or embedded inside of another activity (using {@link ActivityGroup}).
  *
  * There are two methods almost all subclasses of Activity will implement:
- * 
+ *
  * <ul>
  *     <li> {@link #onCreate} is where you initialize your activity.  Most
  *     importantly, here you will usually call {@link #setContentView(int)}
  *     with a layout resource defining your UI, and using {@link #findViewById}
  *     to retrieve the widgets in that UI that you need to interact with
  *     programmatically.
- * 
+ *
  *     <li> {@link #onPause} is where you deal with the user leaving your
  *     activity.  Most importantly, any changes made by the user should at this
  *     point be committed (usually to the
@@ -127,7 +130,7 @@
  * activity classes must have a corresponding
  * {@link android.R.styleable#AndroidManifestActivity &lt;activity&gt;}
  * declaration in their package's <code>AndroidManifest.xml</code>.</p>
- * 
+ *
  * <p>Topics covered here:
  * <ol>
  * <li><a href="#Fragments">Fragments</a>
@@ -170,14 +173,14 @@
  * and becomes the running activity -- the previous activity always remains
  * below it in the stack, and will not come to the foreground again until
  * the new activity exits.</p>
- * 
+ *
  * <p>An activity has essentially four states:</p>
  * <ul>
  *     <li> If an activity in the foreground of the screen (at the top of
  *         the stack),
  *         it is <em>active</em> or  <em>running</em>. </li>
  *     <li>If an activity has lost focus but is still visible (that is, a new non-full-sized
- *         or transparent activity has focus on top of your activity), it 
+ *         or transparent activity has focus on top of your activity), it
  *         is <em>paused</em>. A paused activity is completely alive (it
  *         maintains all state and member information and remains attached to
  *         the window manager), but can be killed by the system in extreme
@@ -197,13 +200,13 @@
  * The square rectangles represent callback methods you can implement to
  * perform operations when the Activity moves between states.  The colored
  * ovals are major states the Activity can be in.</p>
- * 
+ *
  * <p><img src="../../../images/activity_lifecycle.png"
  *      alt="State diagram for an Android Activity Lifecycle." border="0" /></p>
- * 
+ *
  * <p>There are three key loops you may be interested in monitoring within your
  * activity:
- * 
+ *
  * <ul>
  * <li>The <b>entire lifetime</b> of an activity happens between the first call
  * to {@link android.app.Activity#onCreate} through to a single final call
@@ -212,7 +215,7 @@
  * onDestroy().  For example, if it has a thread running in the background
  * to download data from the network, it may create that thread in onCreate()
  * and then stop the thread in onDestroy().
- * 
+ *
  * <li>The <b>visible lifetime</b> of an activity happens between a call to
  * {@link android.app.Activity#onStart} until a corresponding call to
  * {@link android.app.Activity#onStop}.  During this time the user can see the
@@ -224,7 +227,7 @@
  * longer sees what you are displaying.  The onStart() and onStop() methods
  * can be called multiple times, as the activity becomes visible and hidden
  * to the user.
- * 
+ *
  * <li>The <b>foreground lifetime</b> of an activity happens between a call to
  * {@link android.app.Activity#onResume} until a corresponding call to
  * {@link android.app.Activity#onPause}.  During this time the activity is
@@ -234,7 +237,7 @@
  * intent is delivered -- so the code in these methods should be fairly
  * lightweight.
  * </ul>
- * 
+ *
  * <p>The entire lifecycle of an activity is defined by the following
  * Activity methods.  All of these are hooks that you can override
  * to do appropriate work when the activity changes state.  All
@@ -250,7 +253,7 @@
  *     protected void onCreate(Bundle savedInstanceState);
  *
  *     protected void onStart();
- *     
+ *
  *     protected void onRestart();
  *
  *     protected void onResume();
@@ -366,7 +369,7 @@
  * {@link #onSaveInstanceState(Bundle)} is called before placing the activity
  * in such a background state, allowing you to save away any dynamic instance
  * state in your activity into the given Bundle, to be later received in
- * {@link #onCreate} if the activity needs to be re-created.  
+ * {@link #onCreate} if the activity needs to be re-created.
  * See the <a href="#ProcessLifecycle">Process Lifecycle</a>
  * section for more information on how the lifecycle of a process is tied
  * to the activities it is hosting.  Note that it is important to save
@@ -390,14 +393,14 @@
  *
  * <a name="ConfigurationChanges"></a>
  * <h3>Configuration Changes</h3>
- * 
+ *
  * <p>If the configuration of the device (as defined by the
  * {@link Configuration Resources.Configuration} class) changes,
  * then anything displaying a user interface will need to update to match that
  * configuration.  Because Activity is the primary mechanism for interacting
  * with the user, it includes special support for handling configuration
  * changes.</p>
- * 
+ *
  * <p>Unless you specify otherwise, a configuration change (such as a change
  * in screen orientation, language, input devices, etc) will cause your
  * current activity to be <em>destroyed</em>, going through the normal activity
@@ -407,7 +410,7 @@
  * called in that instance then a new instance of the activity will be
  * created, with whatever savedInstanceState the previous instance had generated
  * from {@link #onSaveInstanceState}.</p>
- * 
+ *
  * <p>This is done because any application resource,
  * including layout files, can change based on any configuration value.  Thus
  * the only safe way to handle a configuration change is to re-retrieve all
@@ -415,7 +418,7 @@
  * must already know how to save their state and re-create themselves from
  * that state, this is a convenient way to have an activity restart itself
  * with a new configuration.</p>
- * 
+ *
  * <p>In some special cases, you may want to bypass restarting of your
  * activity based on one or more types of configuration changes.  This is
  * done with the {@link android.R.attr#configChanges android:configChanges}
@@ -425,7 +428,7 @@
  * a configuration change involves any that you do not handle, however, the
  * activity will still be restarted and {@link #onConfigurationChanged}
  * will not be called.</p>
- * 
+ *
  * <a name="StartingActivities"></a>
  * <h3>Starting Activities and Getting Results</h3>
  *
@@ -440,10 +443,10 @@
  * ends.  For example, you may start an activity that lets the user pick
  * a person in a list of contacts; when it ends, it returns the person
  * that was selected.  To do this, you call the
- * {@link android.app.Activity#startActivityForResult(Intent, int)} 
- * version with a second integer parameter identifying the call.  The result 
+ * {@link android.app.Activity#startActivityForResult(Intent, int)}
+ * version with a second integer parameter identifying the call.  The result
  * will come back through your {@link android.app.Activity#onActivityResult}
- * method.</p> 
+ * method.</p>
  *
  * <p>When an activity exits, it can call
  * {@link android.app.Activity#setResult(int)}
@@ -570,17 +573,17 @@
  *
  *     protected void onPause() {
  *         super.onPause();
- * 
+ *
  *         SharedPreferences.Editor ed = mPrefs.edit();
  *         ed.putInt("view_mode", mCurViewMode);
  *         ed.commit();
  *     }
  * }
  * </pre>
- * 
+ *
  * <a name="Permissions"></a>
  * <h3>Permissions</h3>
- * 
+ *
  * <p>The ability to start a particular Activity can be enforced when it is
  * declared in its
  * manifest's {@link android.R.styleable#AndroidManifestActivity &lt;activity&gt;}
@@ -601,10 +604,10 @@
  *
  * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
  * document for more information on permissions and security in general.
- * 
+ *
  * <a name="ProcessLifecycle"></a>
  * <h3>Process Lifecycle</h3>
- * 
+ *
  * <p>The Android system attempts to keep application process around for as
  * long as possible, but eventually will need to remove old processes when
  * memory runs low.  As described in <a href="#ActivityLifecycle">Activity
@@ -614,7 +617,7 @@
  * listed here in order of importance.  The system will kill less important
  * processes (the last ones) before it resorts to killing more important
  * processes (the first ones).
- * 
+ *
  * <ol>
  * <li> <p>The <b>foreground activity</b> (the activity at the top of the screen
  * that the user is currently interacting with) is considered the most important.
@@ -642,7 +645,7 @@
  * context of an activity BroadcastReceiver or Service to ensure that the system
  * knows it needs to keep your process around.
  * </ol>
- * 
+ *
  * <p>Sometimes an Activity may need to do a long-running operation that exists
  * independently of the activity lifecycle itself.  An example may be a camera
  * application that allows you to upload a picture to a web site.  The upload
@@ -720,7 +723,7 @@
         VoiceInteractor voiceInteractor;
     }
     /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
-    
+
     private Window mWindow;
 
     private WindowManager mWindowManager;
@@ -764,7 +767,7 @@
     private final ArrayList<ManagedCursor> mManagedCursors =
         new ArrayList<ManagedCursor>();
 
-    // protected by synchronized (this) 
+    // protected by synchronized (this)
     int mResultCode = RESULT_CANCELED;
     Intent mResultData = null;
 
@@ -775,7 +778,7 @@
 
     private int mDefaultKeyMode = DEFAULT_KEYS_DISABLE;
     private SpannableStringBuilder mDefaultKeySsb = null;
-    
+
     protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
 
     @SuppressWarnings("unused")
@@ -793,16 +796,16 @@
         return mIntent;
     }
 
-    /** 
-     * Change the intent returned by {@link #getIntent}.  This holds a 
-     * reference to the given intent; it does not copy it.  Often used in 
-     * conjunction with {@link #onNewIntent}. 
-     *  
-     * @param newIntent The new Intent object to return from getIntent 
-     * 
+    /**
+     * Change the intent returned by {@link #getIntent}.  This holds a
+     * reference to the given intent; it does not copy it.  Often used in
+     * conjunction with {@link #onNewIntent}.
+     *
+     * @param newIntent The new Intent object to return from getIntent
+     *
      * @see #getIntent
      * @see #onNewIntent
-     */ 
+     */
     public void setIntent(Intent newIntent) {
         mIntent = newIntent;
     }
@@ -816,7 +819,7 @@
     public final boolean isChild() {
         return mParent != null;
     }
-    
+
     /** Return the parent activity if this view is an embedded child. */
     public final Activity getParent() {
         return mParent;
@@ -831,7 +834,7 @@
      * Retrieve the current {@link android.view.Window} for the activity.
      * This can be used to directly access parts of the Window API that
      * are not available through Activity/Screen.
-     * 
+     *
      * @return Window The current window, or null if the activity is not
      *         visual.
      */
@@ -850,7 +853,7 @@
         mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
         return mLoaderManager;
     }
-    
+
     LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
         if (mAllLoaderManagers == null) {
             mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();
@@ -866,13 +869,13 @@
         }
         return lm;
     }
-    
+
     /**
      * Calls {@link android.view.Window#getCurrentFocus} on the
      * Window of this Activity to return the currently focused view.
-     * 
+     *
      * @return View The current View with focus or null.
-     * 
+     *
      * @see #getWindow
      * @see android.view.Window#getCurrentFocus
      */
@@ -888,20 +891,20 @@
      * with widgets in the UI, calling
      * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
      * cursors for data being displayed, etc.
-     * 
+     *
      * <p>You can call {@link #finish} from within this function, in
      * which case onDestroy() will be immediately called without any of the rest
      * of the activity lifecycle ({@link #onStart}, {@link #onResume},
      * {@link #onPause}, etc) executing.
-     * 
+     *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @param savedInstanceState If the activity is being re-initialized after
      *     previously being shut down then this Bundle contains the data it most
      *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
-     * 
+     *
      * @see #onStart
      * @see #onSaveInstanceState
      * @see #onRestoreInstanceState
@@ -996,12 +999,12 @@
      * decide whether to use your default implementation.  The default
      * implementation of this method performs a restore of any view state that
      * had previously been frozen by {@link #onSaveInstanceState}.
-     * 
+     *
      * <p>This method is called between {@link #onStart} and
      * {@link #onPostCreate}.
-     * 
+     *
      * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
-     * 
+     *
      * @see #onCreate
      * @see #onPostCreate
      * @see #onResume
@@ -1098,11 +1101,11 @@
      * and {@link #onRestoreInstanceState} have been called).  Applications will
      * generally not implement this method; it is intended for system
      * classes to do final initialization after application code has run.
-     * 
+     *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @param savedInstanceState If the activity is being re-initialized after
      *     previously being shut down then this Bundle contains the data it most
      *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
@@ -1133,14 +1136,14 @@
     }
 
     /**
-     * Called after {@link #onCreate} &mdash; or after {@link #onRestart} when  
-     * the activity had been stopped, but is now again being displayed to the 
+     * Called after {@link #onCreate} &mdash; or after {@link #onRestart} when
+     * the activity had been stopped, but is now again being displayed to the
      * user.  It will be followed by {@link #onResume}.
      *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @see #onCreate
      * @see #onStop
      * @see #onResume
@@ -1148,7 +1151,7 @@
     protected void onStart() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
         mCalled = true;
-        
+
         if (!mLoadersStarted) {
             mLoadersStarted = true;
             if (mLoaderManager != null) {
@@ -1173,11 +1176,11 @@
      * this is usually the place
      * where the cursor should be requeried (because you had deactivated it in
      * {@link #onStop}.
-     * 
+     *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @see #onStop
      * @see #onStart
      * @see #onResume
@@ -1200,7 +1203,7 @@
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @see #onRestoreInstanceState
      * @see #onRestart
      * @see #onPostResume
@@ -1218,11 +1221,11 @@
      * been called). Applications will generally not implement this method;
      * it is intended for system classes to do final setup after application
      * resume code has run.
-     * 
+     *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @see #onResume
      */
     protected void onPostResume() {
@@ -1256,19 +1259,19 @@
      * activity is re-launched while at the top of the activity stack instead
      * of a new instance of the activity being started, onNewIntent() will be
      * called on the existing instance with the Intent that was used to
-     * re-launch it. 
-     *  
-     * <p>An activity will always be paused before receiving a new intent, so 
-     * you can count on {@link #onResume} being called after this method. 
-     * 
-     * <p>Note that {@link #getIntent} still returns the original Intent.  You 
-     * can use {@link #setIntent} to update it to this new Intent. 
-     * 
-     * @param intent The new intent that was started for the activity. 
-     *  
+     * re-launch it.
+     *
+     * <p>An activity will always be paused before receiving a new intent, so
+     * you can count on {@link #onResume} being called after this method.
+     *
+     * <p>Note that {@link #getIntent} still returns the original Intent.  You
+     * can use {@link #setIntent} to update it to this new Intent.
+     *
+     * @param intent The new intent that was started for the activity.
+     *
      * @see #getIntent
-     * @see #setIntent 
-     * @see #onResume 
+     * @see #setIntent
+     * @see #onResume
      */
     protected void onNewIntent(Intent intent) {
     }
@@ -1342,9 +1345,9 @@
      *
      * <p>If called, this method will occur before {@link #onStop}.  There are
      * no guarantees about whether it will occur before or after {@link #onPause}.
-     * 
+     *
      * @param outState Bundle in which to place your saved state.
-     * 
+     *
      * @see #onCreate
      * @see #onRestoreInstanceState
      * @see #onPause
@@ -1429,23 +1432,23 @@
      * noticeable amount of CPU in order to make the switch to the next activity
      * as fast as possible, or to close resources that are exclusive access
      * such as the camera.
-     * 
+     *
      * <p>In situations where the system needs more memory it may kill paused
      * processes to reclaim resources.  Because of this, you should be sure
      * that all of your state is saved by the time you return from
      * this function.  In general {@link #onSaveInstanceState} is used to save
      * per-instance state in the activity and this method is used to store
      * global persistent data (in content providers, files, etc.)
-     * 
+     *
      * <p>After receiving this call you will usually receive a following call
      * to {@link #onStop} (after the next activity has been resumed and
      * displayed), however in some cases there will be a direct call back to
      * {@link #onResume} without going through the stopped state.
-     * 
+     *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @see #onResume
      * @see #onSaveInstanceState
      * @see #onStop
@@ -1464,32 +1467,32 @@
      * brought to the foreground, {@link #onUserLeaveHint} will not be called on
      * the activity being interrupted.  In cases when it is invoked, this method
      * is called right before the activity's {@link #onPause} callback.
-     * 
+     *
      * <p>This callback and {@link #onUserInteraction} are intended to help
      * activities manage status bar notifications intelligently; specifically,
      * for helping activities determine the proper time to cancel a notfication.
-     * 
+     *
      * @see #onUserInteraction()
      */
     protected void onUserLeaveHint() {
     }
-    
+
     /**
      * Generate a new thumbnail for this activity.  This method is called before
      * pausing the activity, and should draw into <var>outBitmap</var> the
      * imagery for the desired thumbnail in the dimensions of that bitmap.  It
      * can use the given <var>canvas</var>, which is configured to draw into the
      * bitmap, for rendering if desired.
-     * 
+     *
      * <p>The default implementation returns fails and does not draw a thumbnail;
      * this will result in the platform creating its own thumbnail if needed.
-     * 
+     *
      * @param outBitmap The bitmap to contain the thumbnail.
      * @param canvas Can be used to render into the bitmap.
-     * 
+     *
      * @return Return true if you have drawn into the bitmap; otherwise after
      *         you return it will be filled with a default thumbnail.
-     * 
+     *
      * @see #onCreateDescription
      * @see #onSaveInstanceState
      * @see #onPause
@@ -1502,15 +1505,15 @@
      * Generate a new description for this activity.  This method is called
      * before pausing the activity and can, if desired, return some textual
      * description of its current state to be displayed to the user.
-     * 
+     *
      * <p>The default implementation returns null, which will cause you to
      * inherit the description from the previous activity.  If all activities
      * return null, generally the label of the top activity will be used as the
      * description.
-     * 
+     *
      * @return A description of what the user is doing.  It should be short and
      *         sweet (only a few words).
-     * 
+     *
      * @see #onCreateThumbnail
      * @see #onSaveInstanceState
      * @see #onPause
@@ -1538,15 +1541,15 @@
      * Called when you are no longer visible to the user.  You will next
      * receive either {@link #onRestart}, {@link #onDestroy}, or nothing,
      * depending on later user activity.
-     * 
+     *
      * <p>Note that this method may never be called, in low memory situations
      * where the system does not have enough memory to keep your activity's
      * process running after its {@link #onPause} method is called.
-     * 
+     *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @see #onRestart
      * @see #onResume
      * @see #onSaveInstanceState
@@ -1567,7 +1570,7 @@
      * {@link #finish} on it, or because the system is temporarily destroying
      * this instance of the activity to save space.  You can distinguish
      * between these two scenarios with the {@link #isFinishing} method.
-     * 
+     *
      * <p><em>Note: do not count on this method being called as a place for
      * saving data! For example, if an activity is editing data in a content
      * provider, those edits should be committed in either {@link #onPause} or
@@ -1579,11 +1582,11 @@
      * calling this method (or any others) in it, so it should not be used to
      * do things that are intended to remain around after the process goes
      * away.
-     * 
+     *
      * <p><em>Derived classes must call through to the super class's
      * implementation of this method.  If they do not, an exception will be
      * thrown.</em></p>
-     * 
+     *
      * @see #onPause
      * @see #onStop
      * @see #finish
@@ -1657,11 +1660,11 @@
      * by that attribute, then instead of reporting it the system will stop
      * and restart the activity (to have it launched with the new
      * configuration).
-     * 
+     *
      * <p>At the time that this function has been called, your Resources
      * object will have been updated to return resource values matching the
      * new configuration.
-     * 
+     *
      * @param newConfig The new device configuration.
      */
     public void onConfigurationChanged(Configuration newConfig) {
@@ -1681,7 +1684,7 @@
             mActionBar.onConfigurationChanged(newConfig);
         }
     }
-    
+
     /**
      * If this activity is being destroyed because it can not handle a
      * configuration parameter being changed (and thus its
@@ -1691,7 +1694,7 @@
      * destroyed.  Note that there is no guarantee that these will be
      * accurate (other changes could have happened at any time), so you should
      * only use this as an optimization hint.
-     * 
+     *
      * @return Returns a bit field of the configuration parameters that are
      * changing, as defined by the {@link android.content.res.Configuration}
      * class.
@@ -1699,21 +1702,21 @@
     public int getChangingConfigurations() {
         return mConfigChangeFlags;
     }
-    
+
     /**
      * Retrieve the non-configuration instance data that was previously
      * returned by {@link #onRetainNonConfigurationInstance()}.  This will
      * be available from the initial {@link #onCreate} and
      * {@link #onStart} calls to the new instance, allowing you to extract
      * any useful dynamic state from the previous instance.
-     * 
+     *
      * <p>Note that the data you retrieve here should <em>only</em> be used
      * as an optimization for handling configuration changes.  You should always
      * be able to handle getting a null pointer back, and an activity must
      * still be able to restore itself to its previous state (through the
      * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
      * function returns null.
-     * 
+     *
      * @return Returns the object previously returned by
      * {@link #onRetainNonConfigurationInstance()}.
      *
@@ -1727,7 +1730,7 @@
         return mLastNonConfigurationInstances != null
                 ? mLastNonConfigurationInstances.activity : null;
     }
-    
+
     /**
      * Called by the system, as part of destroying an
      * activity due to a configuration change, when it is known that a new
@@ -1736,7 +1739,7 @@
      * itself, which can later be retrieved by calling
      * {@link #getLastNonConfigurationInstance()} in the new activity
      * instance.
-     * 
+     *
      * <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
      * or later, consider instead using a {@link Fragment} with
      * {@link Fragment#setRetainInstance(boolean)
@@ -1756,14 +1759,14 @@
      * the {@link #getLastNonConfigurationInstance()} method of the following
      * activity instance as described there.
      * </ul>
-     * 
+     *
      * <p>These guarantees are designed so that an activity can use this API
      * to propagate extensive state from the old to new activity instance, from
      * loaded bitmaps, to network connections, to evenly actively running
      * threads.  Note that you should <em>not</em> propagate any data that
      * may change based on the configuration, including any data loaded from
      * resources such as strings, layouts, or drawables.
-     * 
+     *
      * <p>The guarantee of no message handling during the switch to the next
      * activity simplifies use with active objects.  For example if your retained
      * state is an {@link android.os.AsyncTask} you are guaranteed that its
@@ -1783,21 +1786,21 @@
     public Object onRetainNonConfigurationInstance() {
         return null;
     }
-    
+
     /**
      * Retrieve the non-configuration instance data that was previously
      * returned by {@link #onRetainNonConfigurationChildInstances()}.  This will
      * be available from the initial {@link #onCreate} and
      * {@link #onStart} calls to the new instance, allowing you to extract
      * any useful dynamic state from the previous instance.
-     * 
+     *
      * <p>Note that the data you retrieve here should <em>only</em> be used
      * as an optimization for handling configuration changes.  You should always
      * be able to handle getting a null pointer back, and an activity must
      * still be able to restore itself to its previous state (through the
      * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
      * function returns null.
-     * 
+     *
      * @return Returns the object previously returned by
      * {@link #onRetainNonConfigurationChildInstances()}
      */
@@ -1806,7 +1809,7 @@
         return mLastNonConfigurationInstances != null
                 ? mLastNonConfigurationInstances.children : null;
     }
-    
+
     /**
      * This method is similar to {@link #onRetainNonConfigurationInstance()} except that
      * it should return either a mapping from  child activity id strings to arbitrary objects,
@@ -1818,7 +1821,7 @@
     HashMap<String,Object> onRetainNonConfigurationChildInstances() {
         return null;
     }
-    
+
     NonConfigurationInstances retainNonConfigurationInstances() {
         Object activity = onRetainNonConfigurationInstance();
         HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
@@ -1846,7 +1849,7 @@
                 && mVoiceInteractor == null) {
             return null;
         }
-        
+
         NonConfigurationInstances nci = new NonConfigurationInstances();
         nci.activity = activity;
         nci.children = children;
@@ -1886,7 +1889,7 @@
             }
         }
     }
-    
+
     /**
      * Called when a Fragment is being attached to this activity, immediately
      * after the call to its {@link Fragment#onAttach Fragment.onAttach()}
@@ -1894,14 +1897,14 @@
      */
     public void onAttachFragment(Fragment fragment) {
     }
-    
+
     /**
      * Wrapper around
      * {@link ContentResolver#query(android.net.Uri , String[], String, String[], String)}
      * that gives the resulting {@link Cursor} to call
      * {@link #startManagingCursor} so that the activity will manage its
      * lifecycle for you.
-     * 
+     *
      * <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
      * or later, consider instead using {@link LoaderManager} instead, available
      * via {@link #getLoaderManager()}.</em>
@@ -1911,14 +1914,14 @@
      * you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
      * not</em> automatically close the cursor and, in that case, you must call
      * {@link Cursor#close()}.</p>
-     * 
+     *
      * @param uri The URI of the content provider to query.
      * @param projection List of columns to return.
      * @param selection SQL WHERE clause.
      * @param sortOrder SQL ORDER BY clause.
-     * 
+     *
      * @return The Cursor that was returned by query().
-     * 
+     *
      * @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
      * @see #startManagingCursor
      * @hide
@@ -1941,7 +1944,7 @@
      * that gives the resulting {@link Cursor} to call
      * {@link #startManagingCursor} so that the activity will manage its
      * lifecycle for you.
-     * 
+     *
      * <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
      * or later, consider instead using {@link LoaderManager} instead, available
      * via {@link #getLoaderManager()}.</em>
@@ -1951,15 +1954,15 @@
      * you call {@link #stopManagingCursor} on a cursor from a managed query, the system <em>will
      * not</em> automatically close the cursor and, in that case, you must call
      * {@link Cursor#close()}.</p>
-     * 
+     *
      * @param uri The URI of the content provider to query.
      * @param projection List of columns to return.
      * @param selection SQL WHERE clause.
      * @param selectionArgs The arguments to selection, if any ?s are pesent
      * @param sortOrder SQL ORDER BY clause.
-     * 
+     *
      * @return The Cursor that was returned by query().
-     * 
+     *
      * @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
      * @see #startManagingCursor
      *
@@ -1982,7 +1985,7 @@
      * {@link Cursor#deactivate} on the given Cursor, and when it is later restarted
      * it will call {@link Cursor#requery} for you.  When the activity is
      * destroyed, all managed Cursors will be closed automatically.
-     * 
+     *
      * <em>If you are targeting {@link android.os.Build.VERSION_CODES#HONEYCOMB}
      * or later, consider instead using {@link LoaderManager} instead, available
      * via {@link #getLoaderManager()}.</em>
@@ -1992,9 +1995,9 @@
      * However, if you call {@link #stopManagingCursor} on a cursor from a managed query, the system
      * <em>will not</em> automatically close the cursor and, in that case, you must call
      * {@link Cursor#close()}.</p>
-     * 
+     *
      * @param c The Cursor to be managed.
-     * 
+     *
      * @see #managedQuery(android.net.Uri , String[], String, String[], String)
      * @see #stopManagingCursor
      *
@@ -2013,13 +2016,13 @@
      * Given a Cursor that was previously given to
      * {@link #startManagingCursor}, stop the activity's management of that
      * cursor.
-     * 
+     *
      * <p><strong>Warning:</strong> After calling this method on a cursor from a managed query,
-     * the system <em>will not</em> automatically close the cursor and you must call 
+     * the system <em>will not</em> automatically close the cursor and you must call
      * {@link Cursor#close()}.</p>
-     * 
+     *
      * @param c The Cursor that was being managed.
-     * 
+     *
      * @see #startManagingCursor
      *
      * @deprecated Use the new {@link android.content.CursorLoader} class with
@@ -2058,7 +2061,7 @@
     public View findViewById(int id) {
         return getWindow().findViewById(id);
     }
-    
+
     /**
      * Retrieve a reference to this activity's ActionBar.
      *
@@ -2094,7 +2097,7 @@
         mActionBar = new ToolbarActionBar(toolbar, getTitle(), this);
         mActionBar.invalidateOptionsMenu();
     }
-    
+
     /**
      * Creates a new ActionBar, locates the inflated ActionBarView,
      * initializes the ActionBar with the view, and sets mActionBar.
@@ -2116,13 +2119,13 @@
         mWindow.setDefaultIcon(mActivityInfo.getIconResource());
         mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
     }
-    
+
     /**
      * Set the activity content from a layout resource.  The resource will be
      * inflated, adding all top-level views to the activity.
      *
      * @param layoutResID Resource ID to be inflated.
-     * 
+     *
      * @see #setContentView(android.view.View)
      * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
      */
@@ -2140,7 +2143,7 @@
      * your own layout parameters, invoke
      * {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
      * instead.
-     * 
+     *
      * @param view The desired content to display.
      *
      * @see #setContentView(int)
@@ -2155,7 +2158,7 @@
      * Set the activity content to an explicit view.  This view is placed
      * directly into the activity's view hierarchy.  It can itself be a complex
      * view hierarchy.
-     * 
+     *
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
      *
@@ -2170,7 +2173,7 @@
     /**
      * Add an additional content view to the activity.  Added after any existing
      * ones in the activity -- existing views are NOT removed.
-     * 
+     *
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
      */
@@ -2235,23 +2238,23 @@
     /**
      * Use with {@link #setDefaultKeyMode} to turn off default handling of
      * keys.
-     * 
+     *
      * @see #setDefaultKeyMode
      */
     static public final int DEFAULT_KEYS_DISABLE = 0;
     /**
      * Use with {@link #setDefaultKeyMode} to launch the dialer during default
      * key handling.
-     * 
+     *
      * @see #setDefaultKeyMode
      */
     static public final int DEFAULT_KEYS_DIALER = 1;
     /**
      * Use with {@link #setDefaultKeyMode} to execute a menu shortcut in
      * default key handling.
-     * 
+     *
      * <p>That is, the user does not need to hold down the menu key to execute menu shortcuts.
-     * 
+     *
      * @see #setDefaultKeyMode
      */
     static public final int DEFAULT_KEYS_SHORTCUT = 2;
@@ -2259,9 +2262,9 @@
      * Use with {@link #setDefaultKeyMode} to specify that unhandled keystrokes
      * will start an application-defined search.  (If the application or activity does not
      * actually define a search, the the keys will be ignored.)
-     * 
+     *
      * <p>See {@link android.app.SearchManager android.app.SearchManager} for more details.
-     * 
+     *
      * @see #setDefaultKeyMode
      */
     static public final int DEFAULT_KEYS_SEARCH_LOCAL = 3;
@@ -2270,9 +2273,9 @@
      * Use with {@link #setDefaultKeyMode} to specify that unhandled keystrokes
      * will start a global search (typically web search, but some platforms may define alternate
      * methods for global search)
-     * 
+     *
      * <p>See {@link android.app.SearchManager android.app.SearchManager} for more details.
-     * 
+     *
      * @see #setDefaultKeyMode
      */
     static public final int DEFAULT_KEYS_SEARCH_GLOBAL = 4;
@@ -2284,16 +2287,16 @@
      * floor. Other modes allow you to launch the dialer
      * ({@link #DEFAULT_KEYS_DIALER}), execute a shortcut in your options
      * menu without requiring the menu key be held down
-     * ({@link #DEFAULT_KEYS_SHORTCUT}), or launch a search ({@link #DEFAULT_KEYS_SEARCH_LOCAL} 
+     * ({@link #DEFAULT_KEYS_SHORTCUT}), or launch a search ({@link #DEFAULT_KEYS_SEARCH_LOCAL}
      * and {@link #DEFAULT_KEYS_SEARCH_GLOBAL}).
-     * 
+     *
      * <p>Note that the mode selected here does not impact the default
      * handling of system keys, such as the "back" and "menu" keys, and your
      * activity and its views always get a first chance to receive and handle
      * all application keys.
-     * 
+     *
      * @param mode The desired default key mode constant.
-     * 
+     *
      * @see #DEFAULT_KEYS_DISABLE
      * @see #DEFAULT_KEYS_DIALER
      * @see #DEFAULT_KEYS_SHORTCUT
@@ -2303,7 +2306,7 @@
      */
     public final void setDefaultKeyMode(@DefaultKeyMode int mode) {
         mDefaultKeyMode = mode;
-        
+
         // Some modes use a SpannableStringBuilder to track & dispatch input events
         // This list must remain in sync with the switch in onKeyDown()
         switch (mode) {
@@ -2324,10 +2327,10 @@
 
     /**
      * Called when a key was pressed down and not handled by any of the views
-     * inside of the activity. So, for example, key presses while the cursor 
+     * inside of the activity. So, for example, key presses while the cursor
      * is inside a TextView will not trigger the event (unless it is a navigation
      * to another object) because TextView handles its own key presses.
-     * 
+     *
      * <p>If the focused view didn't want this event, this method is called.
      *
      * <p>The default implementation takes care of {@link KeyEvent#KEYCODE_BACK}
@@ -2338,12 +2341,12 @@
      * will be performed; for earlier applications, it will perform the
      * action immediately in on-down, as those versions of the platform
      * behaved.
-     * 
+     *
      * <p>Other additional default key handling may be performed
      * if configured with {@link #setDefaultKeyMode}.
-     * 
+     *
      * @return Return <code>true</code> to prevent this event from being propagated
-     * further, or <code>false</code> to indicate that you have not handled 
+     * further, or <code>false</code> to indicate that you have not handled
      * this event and it should continue to be propagated.
      * @see #onKeyUp
      * @see android.view.KeyEvent
@@ -2358,11 +2361,11 @@
             }
             return true;
         }
-        
+
         if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {
             return false;
         } else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {
-            if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL, 
+            if (getWindow().performPanelShortcut(Window.FEATURE_OPTIONS_PANEL,
                     keyCode, event, Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {
                 return true;
             }
@@ -2382,12 +2385,12 @@
 
                     final String str = mDefaultKeySsb.toString();
                     clearSpannable = true;
-                    
+
                     switch (mDefaultKeyMode) {
                     case DEFAULT_KEYS_DIALER:
                         Intent intent = new Intent(Intent.ACTION_DIAL,  Uri.parse("tel:" + str));
                         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        startActivity(intent);    
+                        startActivity(intent);
                         break;
                     case DEFAULT_KEYS_SEARCH_LOCAL:
                         startSearch(str, false, null, false);
@@ -2418,16 +2421,16 @@
 
     /**
      * Called when a key was released and not handled by any of the views
-     * inside of the activity. So, for example, key presses while the cursor 
+     * inside of the activity. So, for example, key presses while the cursor
      * is inside a TextView will not trigger the event (unless it is a navigation
      * to another object) because TextView handles its own key presses.
-     * 
+     *
      * <p>The default implementation handles KEYCODE_BACK to stop the activity
      * and go back.
-     * 
+     *
      * @return Return <code>true</code> to prevent this event from being propagated
-     * further, or <code>false</code> to indicate that you have not handled 
-     * this event and it should continue to be propagated. 
+     * further, or <code>false</code> to indicate that you have not handled
+     * this event and it should continue to be propagated.
      * @see #onKeyDown
      * @see KeyEvent
      */
@@ -2451,7 +2454,7 @@
     public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
         return false;
     }
-    
+
     /**
      * Called when the activity has detected the user's press of the back
      * key.  The default implementation simply finishes the current activity,
@@ -2485,9 +2488,9 @@
      * Called when a touch screen event was not handled by any of the views
      * under it.  This is most useful to process touch events that happen
      * outside of your window bounds, where there is no view to receive it.
-     * 
+     *
      * @param event The touch screen event being processed.
-     * 
+     *
      * @return Return true if you have consumed the event, false if you haven't.
      * The default implementation always returns false.
      */
@@ -2496,10 +2499,10 @@
             finish();
             return true;
         }
-        
+
         return false;
     }
-    
+
     /**
      * Called when the trackball was moved and not handled by any of the
      * views inside of the activity.  So, for example, if the trackball moves
@@ -2508,9 +2511,9 @@
      * here happens <em>before</em> trackball movements are converted to
      * DPAD key events, which then get sent back to the view hierarchy, and
      * will be processed at the point for things like focus navigation.
-     * 
+     *
      * @param event The trackball event being processed.
-     * 
+     *
      * @return Return true if you have consumed the event, false if you haven't.
      * The default implementation always returns false.
      */
@@ -2554,21 +2557,21 @@
      * This callback and {@link #onUserLeaveHint} are intended to help
      * activities manage status bar notifications intelligently; specifically,
      * for helping activities determine the proper time to cancel a notfication.
-     * 
+     *
      * <p>All calls to your activity's {@link #onUserLeaveHint} callback will
      * be accompanied by calls to {@link #onUserInteraction}.  This
      * ensures that your activity will be told of relevant user activity such
      * as pulling down the notification pane and touching an item there.
-     * 
+     *
      * <p>Note that this callback will be invoked for the touch down action
      * that begins a touch gesture, but may not be invoked for the touch-moved
      * and touch-up actions that follow.
-     * 
+     *
      * @see #onUserLeaveHint()
      */
     public void onUserInteraction() {
     }
-    
+
     public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
         // Update window manager if: we have a view, that view is
         // attached to its parent (which will be a RootView), and
@@ -2589,14 +2592,14 @@
      * focus.  This is the best indicator of whether this activity is visible
      * to the user.  The default implementation clears the key tracking
      * state, so should always be called.
-     * 
+     *
      * <p>Note that this provides information about global focus state, which
      * is managed independently of activity lifecycles.  As such, while focus
      * changes will generally have some relation to lifecycle changes (an
      * activity that is stopped will not generally get window focus), you
      * should not rely on any particular order between the callbacks here and
      * those in the other lifecycle methods such as {@link #onResume}.
-     * 
+     *
      * <p>As a general rule, however, a resumed activity will have window
      * focus...  unless it has displayed other dialogs or popups that take
      * input focus, in which case the activity itself will not have focus
@@ -2606,14 +2609,14 @@
      * pausing the foreground activity.
      *
      * @param hasFocus Whether the window of this activity has focus.
-     * 
+     *
      * @see #hasWindowFocus()
      * @see #onResume
      * @see View#onWindowFocusChanged(boolean)
      */
     public void onWindowFocusChanged(boolean hasFocus) {
     }
-    
+
     /**
      * Called when the main window associated with the activity has been
      * attached to the window manager.
@@ -2623,7 +2626,7 @@
      */
     public void onAttachedToWindow() {
     }
-    
+
     /**
      * Called when the main window associated with the activity has been
      * detached from the window manager.
@@ -2633,13 +2636,13 @@
      */
     public void onDetachedFromWindow() {
     }
-    
+
     /**
      * Returns true if this activity's <em>main</em> window currently has window focus.
      * Note that this is not the same as the view itself having focus.
-     * 
+     *
      * @return True if this activity's main window currently has window focus.
-     * 
+     *
      * @see #onWindowAttributesChanged(android.view.WindowManager.LayoutParams)
      */
     public boolean hasWindowFocus() {
@@ -2661,14 +2664,14 @@
     public void onWindowDismissed() {
         finish();
     }
-    
+
     /**
-     * Called to process key events.  You can override this to intercept all 
-     * key events before they are dispatched to the window.  Be sure to call 
+     * Called to process key events.  You can override this to intercept all
+     * key events before they are dispatched to the window.  Be sure to call
      * this implementation for key events that should be handled normally.
-     * 
+     *
      * @param event The key event.
-     * 
+     *
      * @return boolean Return true if this event was consumed.
      */
     public boolean dispatchKeyEvent(KeyEvent event) {
@@ -2713,9 +2716,9 @@
      * intercept all touch screen events before they are dispatched to the
      * window.  Be sure to call this implementation for touch screen events
      * that should be handled normally.
-     * 
+     *
      * @param ev The touch screen event.
-     * 
+     *
      * @return boolean Return true if this event was consumed.
      */
     public boolean dispatchTouchEvent(MotionEvent ev) {
@@ -2727,15 +2730,15 @@
         }
         return onTouchEvent(ev);
     }
-    
+
     /**
      * Called to process trackball events.  You can override this to
      * intercept all trackball events before they are dispatched to the
      * window.  Be sure to call this implementation for trackball events
      * that should be handled normally.
-     * 
+     *
      * @param ev The trackball event.
-     * 
+     *
      * @return boolean Return true if this event was consumed.
      */
     public boolean dispatchTrackballEvent(MotionEvent ev) {
@@ -2830,7 +2833,7 @@
 
     /**
      * {@inheritDoc}
-     * 
+     *
      * @return The default implementation returns true.
      */
     public boolean onMenuOpened(int featureId, Menu menu) {
@@ -2880,7 +2883,7 @@
                     }
                 }
                 return false;
-                
+
             case Window.FEATURE_CONTEXT_MENU:
                 if(titleCondensed != null) {
                     EventLog.writeEvent(50000, 1, titleCondensed.toString());
@@ -2894,7 +2897,7 @@
                 return false;
         }
     }
-    
+
     /**
      * Default implementation of
      * {@link android.view.Window.Callback#onPanelClosed(int, Menu)} for
@@ -2910,7 +2913,7 @@
                 mFragments.dispatchOptionsMenuClosed(menu);
                 onOptionsMenuClosed(menu);
                 break;
-                
+
             case Window.FEATURE_CONTEXT_MENU:
                 onContextMenuClosed(menu);
                 break;
@@ -2932,32 +2935,32 @@
             mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
         }
     }
-    
+
     /**
      * Initialize the contents of the Activity's standard options menu.  You
      * should place your menu items in to <var>menu</var>.
-     * 
+     *
      * <p>This is only called once, the first time the options menu is
      * displayed.  To update the menu every time it is displayed, see
      * {@link #onPrepareOptionsMenu}.
-     * 
+     *
      * <p>The default implementation populates the menu with standard system
-     * menu items.  These are placed in the {@link Menu#CATEGORY_SYSTEM} group so that 
-     * they will be correctly ordered with application-defined menu items. 
-     * Deriving classes should always call through to the base implementation. 
-     * 
+     * menu items.  These are placed in the {@link Menu#CATEGORY_SYSTEM} group so that
+     * they will be correctly ordered with application-defined menu items.
+     * Deriving classes should always call through to the base implementation.
+     *
      * <p>You can safely hold on to <var>menu</var> (and any items created
      * from it), making modifications to it as desired, until the next
      * time onCreateOptionsMenu() is called.
-     * 
+     *
      * <p>When you add items to the menu, you can implement the Activity's
      * {@link #onOptionsItemSelected} method to handle them there.
-     * 
+     *
      * @param menu The options menu in which you place your items.
-     * 
+     *
      * @return You must return true for the menu to be displayed;
      *         if you return false it will not be shown.
-     * 
+     *
      * @see #onPrepareOptionsMenu
      * @see #onOptionsItemSelected
      */
@@ -2973,17 +2976,17 @@
      * called right before the menu is shown, every time it is shown.  You can
      * use this method to efficiently enable/disable items or otherwise
      * dynamically modify the contents.
-     * 
+     *
      * <p>The default implementation updates the system menu items based on the
      * activity's state.  Deriving classes should always call through to the
      * base class implementation.
-     * 
+     *
      * @param menu The options menu as last shown or first initialized by
      *             onCreateOptionsMenu().
-     * 
+     *
      * @return You must return true for the menu to be displayed;
      *         if you return false it will not be shown.
-     * 
+     *
      * @see #onCreateOptionsMenu
      */
     public boolean onPrepareOptionsMenu(Menu menu) {
@@ -3000,15 +3003,15 @@
      * its Handler as appropriate).  You can use this method for any items
      * for which you would like to do processing without those other
      * facilities.
-     * 
+     *
      * <p>Derived classes should call through to the base class for it to
      * perform the default menu handling.</p>
-     * 
+     *
      * @param item The menu item that was selected.
-     * 
+     *
      * @return boolean Return false to allow normal menu processing to
      *         proceed, true to consume it here.
-     * 
+     *
      * @see #onCreateOptionsMenu
      */
     public boolean onOptionsItemSelected(MenuItem item) {
@@ -3125,7 +3128,7 @@
     /**
      * This hook is called whenever the options menu is being closed (either by the user canceling
      * the menu with the back/menu button, or when an item is selected).
-     *  
+     *
      * @param menu The options menu as last shown or first initialized by
      *             onCreateOptionsMenu().
      */
@@ -3134,7 +3137,7 @@
             mParent.onOptionsMenuClosed(menu);
         }
     }
-    
+
     /**
      * Programmatically opens the options menu. If the options menu is already
      * open, this method does nothing.
@@ -3144,7 +3147,7 @@
             mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null);
         }
     }
-    
+
     /**
      * Progammatically closes the options menu. If the options menu is already
      * closed, this method does nothing.
@@ -3175,43 +3178,43 @@
      * {@link OnCreateContextMenuListener} on the view to this activity, so
      * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} will be
      * called when it is time to show the context menu.
-     * 
+     *
      * @see #unregisterForContextMenu(View)
      * @param view The view that should show a context menu.
      */
     public void registerForContextMenu(View view) {
         view.setOnCreateContextMenuListener(this);
     }
-    
+
     /**
      * Prevents a context menu to be shown for the given view. This method will remove the
      * {@link OnCreateContextMenuListener} on the view.
-     * 
+     *
      * @see #registerForContextMenu(View)
      * @param view The view that should stop showing a context menu.
      */
     public void unregisterForContextMenu(View view) {
         view.setOnCreateContextMenuListener(null);
     }
-    
+
     /**
      * Programmatically opens the context menu for a particular {@code view}.
      * The {@code view} should have been added via
      * {@link #registerForContextMenu(View)}.
-     * 
+     *
      * @param view The view to show the context menu for.
      */
     public void openContextMenu(View view) {
         view.showContextMenu();
     }
-    
+
     /**
      * Programmatically closes the most recently opened context menu, if showing.
      */
     public void closeContextMenu() {
         mWindow.closePanel(Window.FEATURE_CONTEXT_MENU);
     }
-    
+
     /**
      * This hook is called whenever an item in a context menu is selected. The
      * default implementation simply returns false to have the normal processing
@@ -3224,7 +3227,7 @@
      * <p>
      * Derived classes should call through to the base class for it to perform
      * the default menu handling.
-     * 
+     *
      * @param item The context menu item that was selected.
      * @return boolean Return false to allow normal context menu processing to
      *         proceed, true to consume it here.
@@ -3240,7 +3243,7 @@
      * This hook is called whenever the context menu is being closed (either by
      * the user canceling the menu with the back/menu button, or when an item is
      * selected).
-     * 
+     *
      * @param menu The context menu that is being closed.
      */
     public void onContextMenuClosed(Menu menu) {
@@ -3309,14 +3312,14 @@
      * Provides an opportunity to prepare a managed dialog before it is being
      * shown.  The default implementation calls through to
      * {@link #onPrepareDialog(int, Dialog)} for compatibility.
-     * 
+     *
      * <p>
      * Override this if you need to update a managed dialog based on the state
      * of the application each time it is shown. For example, a time picker
      * dialog might want to be updated with the current time. You should call
      * through to the superclass's implementation. The default implementation
      * will set this Activity as the owner activity on the Dialog.
-     * 
+     *
      * @param id The id of the managed dialog.
      * @param dialog The dialog.
      * @param args The dialog arguments provided to {@link #showDialog(int, Bundle)}.
@@ -3367,7 +3370,7 @@
      * If you need to rebuild the dialog, call {@link #removeDialog(int)} first.
      * @return Returns true if the Dialog was created; false is returned if
      * it is not created because {@link #onCreateDialog(int, Bundle)} returns false.
-     * 
+     *
      * @see Dialog
      * @see #onCreateDialog(int, Bundle)
      * @see #onPrepareDialog(int, Dialog, Bundle)
@@ -3393,7 +3396,7 @@
             }
             mManagedDialogs.put(id, md);
         }
-        
+
         md.mArgs = args;
         onPrepareDialog(id, md.mDialog, args);
         md.mDialog.show();
@@ -3422,7 +3425,7 @@
         if (mManagedDialogs == null) {
             throw missingDialog(id);
         }
-        
+
         final ManagedDialog md = mManagedDialogs.get(id);
         if (md == null) {
             throw missingDialog(id);
@@ -3449,7 +3452,7 @@
      * <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, this function
      * will not throw an exception if you try to remove an ID that does not
      * currently have an associated dialog.</p>
-     * 
+     *
      * @param id The id of the managed dialog.
      *
      * @see #onCreateDialog(int, Bundle)
@@ -3474,37 +3477,37 @@
 
     /**
      * This hook is called when the user signals the desire to start a search.
-     * 
+     *
      * <p>You can use this function as a simple way to launch the search UI, in response to a
-     * menu item, search button, or other widgets within your activity. Unless overidden, 
+     * menu item, search button, or other widgets within your activity. Unless overidden,
      * calling this function is the same as calling
      * {@link #startSearch startSearch(null, false, null, false)}, which launches
      * search for the current activity as specified in its manifest, see {@link SearchManager}.
-     * 
+     *
      * <p>You can override this function to force global search, e.g. in response to a dedicated
      * search key, or to block search entirely (by simply returning false).
-     * 
+     *
      * @return Returns {@code true} if search launched, and {@code false} if activity blocks it.
      *         The default implementation always returns {@code true}.
-     * 
+     *
      * @see android.app.SearchManager
      */
     public boolean onSearchRequested() {
-        startSearch(null, false, null, false); 
+        startSearch(null, false, null, false);
         return true;
     }
-    
+
     /**
      * This hook is called to launch the search UI.
-     * 
-     * <p>It is typically called from onSearchRequested(), either directly from 
-     * Activity.onSearchRequested() or from an overridden version in any given 
+     *
+     * <p>It is typically called from onSearchRequested(), either directly from
+     * Activity.onSearchRequested() or from an overridden version in any given
      * Activity.  If your goal is simply to activate search, it is preferred to call
      * onSearchRequested(), which may have been overridden elsewhere in your Activity.  If your goal
      * is to inject specific data such as context data, it is preferred to <i>override</i>
      * onSearchRequested(), so that any callers to it will benefit from the override.
-     * 
-     * @param initialQuery Any non-null non-empty string will be inserted as 
+     *
+     * @param initialQuery Any non-null non-empty string will be inserted as
      * pre-entered text in the search query box.
      * @param selectInitialQuery If true, the initial query will be preselected, which means that
      * any further typing will replace it.  This is useful for cases where an entire pre-formed
@@ -3512,15 +3515,15 @@
      * inserted query.  This is useful when the inserted query is text that the user entered,
      * and the user would expect to be able to keep typing.  <i>This parameter is only meaningful
      * if initialQuery is a non-empty string.</i>
-     * @param appSearchData An application can insert application-specific 
-     * context here, in order to improve quality or specificity of its own 
+     * @param appSearchData An application can insert application-specific
+     * context here, in order to improve quality or specificity of its own
      * searches.  This data will be returned with SEARCH intent(s).  Null if
      * no extra data is required.
      * @param globalSearch If false, this will only launch the search that has been specifically
-     * defined by the application (which is usually defined as a local search).  If no default 
+     * defined by the application (which is usually defined as a local search).  If no default
      * search is defined in the current application or activity, global search will be launched.
      * If true, this will always launch a platform-global (e.g. web-based) search instead.
-     * 
+     *
      * @see android.app.SearchManager
      * @see #onSearchRequested
      */
@@ -3528,7 +3531,7 @@
             @Nullable Bundle appSearchData, boolean globalSearch) {
         ensureSearchManager();
         mSearchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(),
-                appSearchData, globalSearch); 
+                appSearchData, globalSearch);
     }
 
     /**
@@ -3550,7 +3553,7 @@
      * Request that key events come to this activity. Use this if your
      * activity has no views with focus, but the activity still wants
      * a chance to process key events.
-     * 
+     *
      * @see android.view.Window#takeKeyEvents
      */
     public void takeKeyEvents(boolean get) {
@@ -3560,12 +3563,12 @@
     /**
      * Enable extended window features.  This is a convenience for calling
      * {@link android.view.Window#requestFeature getWindow().requestFeature()}.
-     * 
+     *
      * @param featureId The desired feature as defined in
      *                  {@link android.view.Window}.
      * @return Returns true if the requested feature is supported and now
      *         enabled.
-     * 
+     *
      * @see android.view.Window#requestFeature
      */
     public final boolean requestWindowFeature(int featureId) {
@@ -3677,7 +3680,7 @@
      * Launch an activity for which you would like a result when it finished.
      * When this activity exits, your
      * onActivityResult() method will be called with the given requestCode.
-     * Using a negative requestCode is the same as calling 
+     * Using a negative requestCode is the same as calling
      * {@link #startActivity} (the activity is not launched as a sub-activity).
      *
      * <p>Note that this method should only be used with Intent protocols
@@ -3687,7 +3690,7 @@
      * are launching uses the singleTask launch mode, it will not run in your
      * task and thus you will immediately receive a cancel result.
      *
-     * <p>As a special case, if you call startActivityForResult() with a requestCode 
+     * <p>As a special case, if you call startActivityForResult() with a requestCode
      * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
      * activity, then your window will not be displayed until a result is
      * returned back from the started activity.  This is to avoid visible
@@ -3845,7 +3848,7 @@
      * here; otherwise, its associated action will be executed (such as
      * sending a broadcast) as if you had called
      * {@link IntentSender#sendIntent IntentSender.sendIntent} on it.
-     * 
+     *
      * @param intent The IntentSender to launch.
      * @param requestCode If >= 0, this code will be returned in
      *                    onActivityResult() when the activity exits.
@@ -3936,19 +3939,19 @@
      * information, the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag is not
      * required; if not specified, the new activity will be added to the
      * task of the caller.
-     * 
+     *
      * <p>This method throws {@link android.content.ActivityNotFoundException}
      * if there was no Activity found to run the given Intent.
-     * 
-     * @param intent The intent to start. 
+     *
+     * @param intent The intent to start.
      * @param options Additional options for how the Activity should be started.
      * See {@link android.content.Context#startActivity(Intent, Bundle)
      * Context.startActivity(Intent, Bundle)} for more details.
-     * 
+     *
      * @throws android.content.ActivityNotFoundException
      *
      * @see {@link #startActivity(Intent)}
-     * @see #startActivityForResult 
+     * @see #startActivityForResult
      */
     @Override
     public void startActivity(Intent intent, @Nullable Bundle options) {
@@ -4008,7 +4011,7 @@
     /**
      * Same as calling {@link #startIntentSender(IntentSender, Intent, int, int, int, Bundle)}
      * with no options.
-     * 
+     *
      * @param intent The IntentSender to launch.
      * @param fillInIntent If non-null, this will be provided as the
      * intent parameter to {@link IntentSender#sendIntent}.
@@ -4081,19 +4084,19 @@
     /**
      * A special variation to launch an activity only if a new activity
      * instance is needed to handle the given Intent.  In other words, this is
-     * just like {@link #startActivityForResult(Intent, int)} except: if you are 
+     * just like {@link #startActivityForResult(Intent, int)} except: if you are
      * using the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} flag, or
-     * singleTask or singleTop 
+     * singleTask or singleTop
      * {@link android.R.styleable#AndroidManifestActivity_launchMode launchMode},
-     * and the activity 
-     * that handles <var>intent</var> is the same as your currently running 
-     * activity, then a new instance is not needed.  In this case, instead of 
-     * the normal behavior of calling {@link #onNewIntent} this function will 
-     * return and you can handle the Intent yourself. 
-     * 
+     * and the activity
+     * that handles <var>intent</var> is the same as your currently running
+     * activity, then a new instance is not needed.  In this case, instead of
+     * the normal behavior of calling {@link #onNewIntent} this function will
+     * return and you can handle the Intent yourself.
+     *
      * <p>This function can only be called from a top-level activity; if it is
      * called from a child activity, a runtime exception will be thrown.
-     * 
+     *
      * @param intent The intent to start.
      * @param requestCode If >= 0, this code will be returned in
      *         onActivityResult() when the activity exits, as described in
@@ -4101,10 +4104,10 @@
      * @param options Additional options for how the Activity should be started.
      * See {@link android.content.Context#startActivity(Intent, Bundle)
      * Context.startActivity(Intent, Bundle)} for more details.
-     * 
+     *
      * @return If a new activity was launched then true is returned; otherwise
      *         false is returned and you must handle the Intent yourself.
-     *  
+     *
      * @see #startActivity
      * @see #startActivityForResult
      */
@@ -4167,7 +4170,7 @@
      * other activity components.  You can use this to hand the Intent off
      * to the next Activity that can handle it.  You typically call this in
      * {@link #onCreate} with the Intent returned by {@link #getIntent}.
-     * 
+     *
      * @param intent The intent to dispatch to the next activity.  For
      * correct behavior, this must be the same as the Intent that started
      * your own activity; the only changes you can make are to the extras
@@ -4175,7 +4178,7 @@
      * @param options Additional options for how the Activity should be started.
      * See {@link android.content.Context#startActivity(Intent, Bundle)
      * Context.startActivity(Intent, Bundle)} for more details.
-     * 
+     *
      * @return Returns a boolean indicating whether there was another Activity
      * to start: true if there was a next activity to start, false if there
      * wasn't.  In general, if true is returned you will then want to call
@@ -4217,23 +4220,23 @@
     }
 
     /**
-     * This is called when a child activity of this one calls its 
+     * This is called when a child activity of this one calls its
      * {@link #startActivity} or {@link #startActivityForResult} method.
-     * 
+     *
      * <p>This method throws {@link android.content.ActivityNotFoundException}
      * if there was no Activity found to run the given Intent.
-     * 
+     *
      * @param child The activity making the call.
      * @param intent The intent to start.
      * @param requestCode Reply request code.  < 0 if reply is not requested.
      * @param options Additional options for how the Activity should be started.
      * See {@link android.content.Context#startActivity(Intent, Bundle)
      * Context.startActivity(Intent, Bundle)} for more details.
-     * 
+     *
      * @throws android.content.ActivityNotFoundException
-     * 
-     * @see #startActivity 
-     * @see #startActivityForResult 
+     *
+     * @see #startActivity
+     * @see #startActivityForResult
      */
     public void startActivityFromChild(@NonNull Activity child, Intent intent,
             int requestCode, @Nullable Bundle options) {
@@ -4267,24 +4270,24 @@
     }
 
     /**
-     * This is called when a Fragment in this activity calls its 
+     * This is called when a Fragment in this activity calls its
      * {@link Fragment#startActivity} or {@link Fragment#startActivityForResult}
      * method.
-     * 
+     *
      * <p>This method throws {@link android.content.ActivityNotFoundException}
      * if there was no Activity found to run the given Intent.
-     * 
+     *
      * @param fragment The fragment making the call.
      * @param intent The intent to start.
-     * @param requestCode Reply request code.  < 0 if reply is not requested. 
+     * @param requestCode Reply request code.  < 0 if reply is not requested.
      * @param options Additional options for how the Activity should be started.
      * See {@link android.content.Context#startActivity(Intent, Bundle)
      * Context.startActivity(Intent, Bundle)} for more details.
-     * 
+     *
      * @throws android.content.ActivityNotFoundException
-     * 
-     * @see Fragment#startActivity 
-     * @see Fragment#startActivityForResult 
+     *
+     * @see Fragment#startActivity
+     * @see Fragment#startActivityForResult
      */
     public void startActivityFromFragment(@NonNull Fragment fragment, Intent intent,
             int requestCode, @Nullable Bundle options) {
@@ -4352,14 +4355,14 @@
         } catch (RemoteException e) {
         }
     }
-    
+
     /**
      * Call this to set the result that your activity will return to its
      * caller.
-     * 
+     *
      * @param resultCode The result code to propagate back to the originating
      *                   activity, often RESULT_CANCELED or RESULT_OK
-     * 
+     *
      * @see #RESULT_CANCELED
      * @see #RESULT_OK
      * @see #RESULT_FIRST_USER
@@ -4388,7 +4391,7 @@
      * @param resultCode The result code to propagate back to the originating
      *                   activity, often RESULT_CANCELED or RESULT_OK
      * @param data The data to propagate back to the originating activity.
-     * 
+     *
      * @see #RESULT_CANCELED
      * @see #RESULT_OK
      * @see #RESULT_FIRST_USER
@@ -4406,10 +4409,10 @@
      * the data in {@link #setResult setResult()} will be sent to.  You can
      * use this information to validate that the recipient is allowed to
      * receive the data.
-     * 
+     *
      * <p class="note">Note: if the calling activity is not expecting a result (that is it
-     * did not use the {@link #startActivityForResult} 
-     * form that includes a request code), then the calling package will be 
+     * did not use the {@link #startActivityForResult}
+     * form that includes a request code), then the calling package will be
      * null.</p>
      *
      * <p class="note">Note: prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
@@ -4417,7 +4420,7 @@
      * package was no longer running, it would return null instead of the proper package
      * name.  You can use {@link #getCallingActivity()} and retrieve the package name
      * from that instead.</p>
-     * 
+     *
      * @return The package of the activity that will receive your
      *         reply, or null if none.
      */
@@ -4435,12 +4438,12 @@
      * who the data in {@link #setResult setResult()} will be sent to.  You
      * can use this information to validate that the recipient is allowed to
      * receive the data.
-     * 
+     *
      * <p class="note">Note: if the calling activity is not expecting a result (that is it
-     * did not use the {@link #startActivityForResult} 
-     * form that includes a request code), then the calling package will be 
-     * null. 
-     * 
+     * did not use the {@link #startActivityForResult}
+     * form that includes a request code), then the calling package will be
+     * null.
+     *
      * @return The ComponentName of the activity that will receive your
      *         reply, or null if none.
      */
@@ -4459,7 +4462,7 @@
      * UI itself, but can't just finish prior to onResume() because it needs
      * to wait for a service binding or such.  Setting this to false allows
      * you to prevent your UI from being shown during that time.
-     * 
+     *
      * <p>The default value for this is taken from the
      * {@link android.R.attr#windowNoDisplay} attribute of the activity's theme.
      */
@@ -4472,7 +4475,7 @@
             }
         }
     }
-    
+
     void makeVisible() {
         if (!mWindowAdded) {
             ViewManager wm = getWindowManager();
@@ -4481,16 +4484,16 @@
         }
         mDecor.setVisibility(View.VISIBLE);
     }
-    
+
     /**
      * Check to see whether this activity is in the process of finishing,
      * either because you called {@link #finish} on it or someone else
      * has requested that it finished.  This is often used in
      * {@link #onPause} to determine whether the activity is simply pausing or
      * completely finishing.
-     * 
+     *
      * @return If the activity is finishing, returns true; else returns false.
-     * 
+     *
      * @see #finish
      */
     public boolean isFinishing() {
@@ -4510,7 +4513,7 @@
      * recreated with a new configuration. This is often used in
      * {@link #onStop} to determine whether the state needs to be cleaned up or will be passed
      * on to the next instance of the activity via {@link #onRetainNonConfigurationInstance()}.
-     * 
+     *
      * @return If the activity is being torn down in order to be recreated with a new configuration,
      * returns true; else returns false.
      */
@@ -4603,12 +4606,12 @@
     }
 
     /**
-     * This is called when a child activity of this one calls its 
+     * This is called when a child activity of this one calls its
      * {@link #finish} method.  The default implementation simply calls
      * finish() on this activity (the parent), finishing the entire group.
-     * 
+     *
      * @param child The activity making the call.
-     * 
+     *
      * @see #finish
      */
     public void finishFromChild(Activity child) {
@@ -4631,7 +4634,7 @@
     /**
      * Force finish another activity that you had previously started with
      * {@link #startActivityForResult}.
-     * 
+     *
      * @param requestCode The request code of the activity that you had
      *                    given to startActivityForResult().  If there are multiple
      *                    activities started with this request code, they
@@ -4653,7 +4656,7 @@
     /**
      * This is called when a child activity of this one calls its
      * finishActivity().
-     * 
+     *
      * @param child The activity making the call.
      * @param requestCode Request code that had been used to start the
      *                    activity.
@@ -4681,10 +4684,10 @@
      * data from it.  The <var>resultCode</var> will be
      * {@link #RESULT_CANCELED} if the activity explicitly returned that,
      * didn't return any result, or crashed during its operation.
-     * 
+     *
      * <p>You will receive this call immediately before onResume() when your
      * activity is re-starting.
-     * 
+     *
      * @param requestCode The integer request code originally supplied to
      *                    startActivityForResult(), allowing you to identify who this
      *                    result came from.
@@ -4692,7 +4695,7 @@
      *                   through its setResult().
      * @param data An Intent, which can return result data to the caller
      *               (various data can be attached to Intent "extras").
-     * 
+     *
      * @see #startActivityForResult
      * @see #createPendingResult
      * @see #setResult(int)
@@ -4722,12 +4725,12 @@
     }
 
     /**
-     * Create a new PendingIntent object which you can hand to others 
-     * for them to use to send result data back to your 
-     * {@link #onActivityResult} callback.  The created object will be either 
-     * one-shot (becoming invalid after a result is sent back) or multiple 
-     * (allowing any number of results to be sent through it). 
-     *  
+     * Create a new PendingIntent object which you can hand to others
+     * for them to use to send result data back to your
+     * {@link #onActivityResult} callback.  The created object will be either
+     * one-shot (becoming invalid after a result is sent back) or multiple
+     * (allowing any number of results to be sent through it).
+     *
      * @param requestCode Private request code for the sender that will be
      * associated with the result data when it is returned.  The sender can not
      * modify this value, allowing you to identify incoming results.
@@ -4740,12 +4743,12 @@
      * or any of the flags as supported by
      * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
      * of the intent that can be supplied when the actual send happens.
-     * 
+     *
      * @return Returns an existing or new PendingIntent matching the given
      * parameters.  May return null only if
      * {@link PendingIntent#FLAG_NO_CREATE PendingIntent.FLAG_NO_CREATE} has been
      * supplied.
-     * 
+     *
      * @see PendingIntent
      */
     public PendingIntent createPendingResult(int requestCode, @NonNull Intent data,
@@ -4772,7 +4775,7 @@
      * orientation, the screen will immediately be changed (possibly causing
      * the activity to be restarted). Otherwise, this will be used the next
      * time the activity is visible.
-     * 
+     *
      * @param requestedOrientation An orientation constant as used in
      * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}.
      */
@@ -4788,13 +4791,13 @@
             mParent.setRequestedOrientation(requestedOrientation);
         }
     }
-    
+
     /**
      * Return the current requested orientation of the activity.  This will
      * either be the orientation requested in its component's manifest, or
      * the last requested orientation given to
      * {@link #setRequestedOrientation(int)}.
-     * 
+     *
      * @return Returns an orientation constant as used in
      * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}.
      */
@@ -4812,11 +4815,11 @@
         }
         return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     }
-    
+
     /**
      * Return the identifier of the task this activity is in.  This identifier
      * will remain the same for the lifetime of the activity.
-     * 
+     *
      * @return Task identifier, an opaque integer.
      */
     public int getTaskId() {
@@ -4831,7 +4834,7 @@
     /**
      * Return whether this activity is the root of a task.  The root is the
      * first activity in a task.
-     * 
+     *
      * @return True if this is the root activity, else false.
      */
     public boolean isTaskRoot() {
@@ -4846,11 +4849,11 @@
     /**
      * Move the task containing this activity to the back of the activity
      * stack.  The activity's order within the task is unchanged.
-     * 
+     *
      * @param nonRoot If false then this only works if the activity is the root
      *                of a task; if true it will work for any activity in
      *                a task.
-     * 
+     *
      * @return If the task was moved (or it was already at the
      *         back) true is returned, else false.
      */
@@ -4867,7 +4870,7 @@
     /**
      * Returns class name for this activity with the package prefix removed.
      * This is the default name used to read and write settings.
-     * 
+     *
      * @return The local class name.
      */
     @NonNull
@@ -4881,10 +4884,10 @@
         }
         return cls.substring(packageLen+1);
     }
-    
+
     /**
      * Returns complete component name of this activity.
-     * 
+     *
      * @return Returns the complete component name for this activity
      */
     public ComponentName getComponentName()
@@ -4897,9 +4900,9 @@
      * that are private to this activity.  This simply calls the underlying
      * {@link #getSharedPreferences(String, int)} method by passing in this activity's
      * class name as the preferences name.
-     * 
-     * @param mode Operating mode.  Use {@link #MODE_PRIVATE} for the default 
-     *             operation, {@link #MODE_WORLD_READABLE} and 
+     *
+     * @param mode Operating mode.  Use {@link #MODE_PRIVATE} for the default
+     *             operation, {@link #MODE_WORLD_READABLE} and
      *             {@link #MODE_WORLD_WRITEABLE} to control permissions.
      *
      * @return Returns the single SharedPreferences instance that can be used
@@ -4908,12 +4911,12 @@
     public SharedPreferences getPreferences(int mode) {
         return getSharedPreferences(getLocalClassName(), mode);
     }
-    
+
     private void ensureSearchManager() {
         if (mSearchManager != null) {
             return;
         }
-        
+
         mSearchManager = new SearchManager(this, null);
     }
 
@@ -5031,7 +5034,7 @@
      * <p>
      * In order for the progress bar to be shown, the feature must be requested
      * via {@link #requestWindowFeature(int)}.
-     * 
+     *
      * @param visible Whether to show the progress bars in the title.
      */
     public final void setProgressBarVisibility(boolean visible) {
@@ -5051,14 +5054,14 @@
         getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
                 visible ? Window.PROGRESS_VISIBILITY_ON : Window.PROGRESS_VISIBILITY_OFF);
     }
-    
+
     /**
      * Sets whether the horizontal progress bar in the title should be indeterminate (the circular
      * is always indeterminate).
      * <p>
      * In order for the progress bar to be shown, the feature must be requested
      * via {@link #requestWindowFeature(int)}.
-     * 
+     *
      * @param indeterminate Whether the horizontal progress bar should be indeterminate.
      */
     public final void setProgressBarIndeterminate(boolean indeterminate) {
@@ -5066,13 +5069,13 @@
                 indeterminate ? Window.PROGRESS_INDETERMINATE_ON
                         : Window.PROGRESS_INDETERMINATE_OFF);
     }
-    
+
     /**
      * Sets the progress for the progress bars in the title.
      * <p>
      * In order for the progress bar to be shown, the feature must be requested
      * via {@link #requestWindowFeature(int)}.
-     * 
+     *
      * @param progress The progress for the progress bar. Valid ranges are from
      *            0 to 10000 (both inclusive). If 10000 is given, the progress
      *            bar will be completely filled and will fade out.
@@ -5080,7 +5083,7 @@
     public final void setProgress(int progress) {
         getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress + Window.PROGRESS_START);
     }
-    
+
     /**
      * Sets the secondary progress for the progress bar in the title. This
      * progress is drawn between the primary progress (set via
@@ -5090,7 +5093,7 @@
      * <p>
      * In order for the progress bar to be shown, the feature must be requested
      * via {@link #requestWindowFeature(int)}.
-     * 
+     *
      * @param secondaryProgress The secondary progress for the progress bar. Valid ranges are from
      *            0 to 10000 (both inclusive).
      */
@@ -5104,16 +5107,16 @@
      * volume controls.
      * <p>
      * The suggested audio stream will be tied to the window of this Activity.
-     * If the Activity is switched, the stream set here is no longer the
-     * suggested stream. The client does not need to save and restore the old
-     * suggested stream value in onPause and onResume.
-     * 
+     * Volume requests which are received while the Activity is in the
+     * foreground will affect this stream.
+     * <p>
+     * It is not guaranteed that the hardware volume controls will always change
+     * this stream's volume (for example, if a call is in progress, its stream's
+     * volume may be changed instead). To reset back to the default, use
+     * {@link AudioManager#USE_DEFAULT_STREAM_TYPE}.
+     *
      * @param streamType The type of the audio stream whose volume should be
-     *        changed by the hardware volume controls. It is not guaranteed that
-     *        the hardware volume controls will always change this stream's
-     *        volume (for example, if a call is in progress, its stream's volume
-     *        may be changed instead). To reset back to the default, use
-     *        {@link AudioManager#USE_DEFAULT_STREAM_TYPE}.
+     *            changed by the hardware volume controls.
      */
     public final void setVolumeControlStream(int streamType) {
         getWindow().setVolumeControlStream(streamType);
@@ -5122,7 +5125,7 @@
     /**
      * Gets the suggested audio stream whose volume should be changed by the
      * hardware volume controls.
-     * 
+     *
      * @return The suggested audio stream type whose volume should be changed by
      *         the hardware volume controls.
      * @see #setVolumeControlStream(int)
@@ -5130,7 +5133,40 @@
     public final int getVolumeControlStream() {
         return getWindow().getVolumeControlStream();
     }
-    
+
+    /**
+     * Sets a {@link MediaController} to send media keys and volume changes to.
+     * <p>
+     * The controller will be tied to the window of this Activity. Media key and
+     * volume events which are received while the Activity is in the foreground
+     * will be forwarded to the controller and used to invoke transport controls
+     * or adjust the volume. This may be used instead of or in addition to
+     * {@link #setVolumeControlStream} to affect a specific session instead of a
+     * specific stream.
+     * <p>
+     * It is not guaranteed that the hardware volume controls will always change
+     * this session's volume (for example, if a call is in progress, its
+     * stream's volume may be changed instead). To reset back to the default use
+     * null as the controller.
+     *
+     * @param controller The controller for the session which should receive
+     *            media keys and volume changes.
+     */
+    public final void setMediaController(MediaController controller) {
+        getWindow().setMediaController(controller);
+    }
+
+    /**
+     * Gets the controller which should be receiving media key and volume events
+     * while this activity is in the foreground.
+     *
+     * @return The controller which should receive events.
+     * @see #setMediaController(android.media.session.MediaController)
+     */
+    public final MediaController getMediaController() {
+        return getWindow().getMediaController();
+    }
+
     /**
      * Runs the specified action on the UI thread. If the current thread is the UI
      * thread, then the action is executed immediately. If the current thread is
@@ -5176,7 +5212,7 @@
         if (!"fragment".equals(name)) {
             return onCreateView(name, context, attrs);
         }
-        
+
         return mFragments.onCreateView(parent, name, context, attrs);
     }
 
@@ -5737,7 +5773,7 @@
     }
 
     // ------------------ Internal API ------------------
-    
+
     final void setParent(Activity parent) {
         mParent = parent;
     }
@@ -5751,7 +5787,7 @@
         attachBaseContext(context);
 
         mFragments.attachActivity(this, mContainer, null);
-        
+
         mWindow = PolicyManager.makeNewWindow(this);
         mWindow.setCallback(this);
         mWindow.setOnWindowDismissedCallback(this);
@@ -5846,7 +5882,7 @@
         }
         mActivityTransitionState.enterReady(this);
     }
-    
+
     final void performRestart() {
         mFragments.noteStateNotSaved();
 
@@ -5885,14 +5921,14 @@
             performStart();
         }
     }
-    
+
     final void performResume() {
         performRestart();
-        
+
         mFragments.execPendingActions();
-        
+
         mLastNonConfigurationInstances = null;
-        
+
         mCalled = false;
         // mResumed is set by the instrumentation
         mInstrumentation.callActivityOnResume(this);
@@ -5904,10 +5940,10 @@
 
         // Now really resume, and install the current status bar and menu.
         mCalled = false;
-        
+
         mFragments.dispatchResume();
         mFragments.execPendingActions();
-        
+
         onPostResume();
         if (!mCalled) {
             throw new SuperNotCalledException(
@@ -5930,12 +5966,12 @@
         }
         mResumed = false;
     }
-    
+
     final void performUserLeaving() {
         onUserInteraction();
         onUserLeaveHint();
     }
-    
+
     final void performStop() {
         mDoReportFullyDrawn = false;
         if (mLoadersStarted) {
@@ -5948,7 +5984,7 @@
                 }
             }
         }
-        
+
         if (!mStopped) {
             if (mWindow != null) {
                 mWindow.closeAllPanels();
@@ -5957,9 +5993,9 @@
             if (mToken != null && mParent == null) {
                 WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
             }
-            
+
             mFragments.dispatchStop();
-            
+
             mCalled = false;
             mInstrumentation.callActivityOnStop(this);
             if (!mCalled) {
@@ -5967,7 +6003,7 @@
                     "Activity " + mComponent.toShortString() +
                     " did not call through to super.onStop()");
             }
-    
+
             synchronized (mManagedCursors) {
                 final int N = mManagedCursors.size();
                 for (int i=0; i<N; i++) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e1d0b86..c8cab6f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2456,7 +2456,10 @@
     }
 
     /**
-     * @hide
+     * Return whether currently in lock task mode.  When in this mode
+     * no new tasks can be created or switched to.
+     *
+     * @see Activity#startLockTask()
      */
     public boolean isInLockTaskMode() {
         try {
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 15be9b1..e074219 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -403,20 +403,18 @@
         view.layout(left, top, right, bottom);
     }
 
-    protected ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
+    protected ArrayList<SharedElementOriginalState> setSharedElementState(
             Bundle sharedElementState, final ArrayList<View> snapshots) {
-        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
-                new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
+        ArrayList<SharedElementOriginalState> originalImageState =
+                new ArrayList<SharedElementOriginalState>();
         if (sharedElementState != null) {
             int[] tempLoc = new int[2];
             for (int i = 0; i < mSharedElementNames.size(); i++) {
                 View sharedElement = mSharedElements.get(i);
                 String name = mSharedElementNames.get(i);
-                Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
+                SharedElementOriginalState originalState = getOldSharedElementState(sharedElement,
                         name, sharedElementState);
-                if (originalState != null) {
-                    originalImageState.put((ImageView) sharedElement, originalState);
-                }
+                originalImageState.add(originalState);
                 View parent = (View) sharedElement.getParent();
                 parent.getLocationOnScreen(tempLoc);
                 setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
@@ -438,29 +436,34 @@
         return originalImageState;
     }
 
-    private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
+    private static SharedElementOriginalState getOldSharedElementState(View view, String name,
             Bundle transitionArgs) {
+
+        SharedElementOriginalState state = new SharedElementOriginalState();
+        state.mLeft = view.getLeft();
+        state.mTop = view.getTop();
+        state.mRight = view.getRight();
+        state.mBottom = view.getBottom();
+        state.mMeasuredWidth = view.getMeasuredWidth();
+        state.mMeasuredHeight = view.getMeasuredHeight();
         if (!(view instanceof ImageView)) {
-            return null;
+            return state;
         }
         Bundle bundle = transitionArgs.getBundle(name);
         if (bundle == null) {
-            return null;
+            return state;
         }
         int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
         if (scaleTypeInt < 0) {
-            return null;
+            return state;
         }
 
         ImageView imageView = (ImageView) view;
-        ImageView.ScaleType originalScaleType = imageView.getScaleType();
-
-        Matrix originalMatrix = null;
-        if (originalScaleType == ImageView.ScaleType.MATRIX) {
-            originalMatrix = new Matrix(imageView.getImageMatrix());
+        state.mScaleType = imageView.getScaleType();
+        if (state.mScaleType == ImageView.ScaleType.MATRIX) {
+            state.mMatrix = new Matrix(imageView.getImageMatrix());
         }
-
-        return Pair.create(originalScaleType, originalMatrix);
+        return state;
     }
 
     protected ArrayList<View> createSnapshots(Bundle state, Collection<String> names) {
@@ -489,13 +492,26 @@
         return snapshots;
     }
 
-    protected static void setOriginalImageViewState(
-            ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
+    protected static void setOriginalSharedElementState(ArrayList<View> sharedElements,
+            ArrayList<SharedElementOriginalState> originalState) {
         for (int i = 0; i < originalState.size(); i++) {
-            ImageView imageView = originalState.keyAt(i);
-            Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
-            imageView.setScaleType(state.first);
-            imageView.setImageMatrix(state.second);
+            View view = sharedElements.get(i);
+            SharedElementOriginalState state = originalState.get(i);
+            if (view instanceof ImageView && state.mScaleType != null) {
+                ImageView imageView = (ImageView) view;
+                imageView.setScaleType(state.mScaleType);
+                if (state.mScaleType == ImageView.ScaleType.MATRIX) {
+                  imageView.setImageMatrix(state.mMatrix);
+                }
+            }
+            // origignal widthspec might be AT_MOST,  but it should work for most
+            // cases.
+            int widthSpec = View.MeasureSpec.makeMeasureSpec(state.mMeasuredWidth,
+                    View.MeasureSpec.EXACTLY);
+            int heightSpec = View.MeasureSpec.makeMeasureSpec(state.mMeasuredHeight,
+                    View.MeasureSpec.EXACTLY);
+            view.measure(widthSpec, heightSpec);
+            view.layout(state.mLeft, state.mTop, state.mRight, state.mBottom);
         }
     }
 
@@ -622,4 +638,15 @@
         }
     }
 
+    static class SharedElementOriginalState {
+        int mLeft;
+        int mTop;
+        int mRight;
+        int mBottom;
+        int mMeasuredWidth;
+        int mMeasuredHeight;
+        ImageView.ScaleType mScaleType;
+        Matrix mMatrix;
+    }
+
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 2935b8e..4730559 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -33,6 +33,7 @@
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
+import android.content.pm.KeySet;
 import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
@@ -52,6 +53,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -59,6 +61,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Display;
+import com.android.internal.util.Preconditions;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -1447,6 +1450,62 @@
         return false;
     }
 
+    @Override
+    public KeySet getKeySetByAlias(String packageName, String alias) {
+        Preconditions.checkNotNull(packageName);
+        Preconditions.checkNotNull(alias);
+        IBinder keySetToken;
+        try {
+            keySetToken = mPM.getKeySetByAlias(packageName, alias);
+        } catch (RemoteException e) {
+            return null;
+        }
+        if (keySetToken == null) {
+            return null;
+        }
+        return new KeySet(keySetToken);
+    }
+
+    @Override
+    public KeySet getSigningKeySet(String packageName) {
+        Preconditions.checkNotNull(packageName);
+        IBinder keySetToken;
+        try {
+            keySetToken = mPM.getSigningKeySet(packageName);
+        } catch (RemoteException e) {
+            return null;
+        }
+        if (keySetToken == null) {
+            return null;
+        }
+        return new KeySet(keySetToken);
+    }
+
+
+    @Override
+    public boolean isSignedBy(String packageName, KeySet ks) {
+        Preconditions.checkNotNull(packageName);
+        Preconditions.checkNotNull(ks);
+        IBinder keySetToken = ks.getToken();
+        try {
+            return mPM.isPackageSignedByKeySet(packageName, keySetToken);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isSignedByExactly(String packageName, KeySet ks) {
+        Preconditions.checkNotNull(packageName);
+        Preconditions.checkNotNull(ks);
+        IBinder keySetToken = ks.getToken();
+        try {
+            return mPM.isPackageSignedByKeySetExactly(packageName, keySetToken);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bbfb05e..b9de220 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -247,6 +247,8 @@
     @GuardedBy("mSync")
     private File mFilesDir;
     @GuardedBy("mSync")
+    private File mNoBackupFilesDir;
+    @GuardedBy("mSync")
     private File mCacheDir;
 
     @GuardedBy("mSync")
@@ -558,9 +560,7 @@
 
         registerService(TELECOMM_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(TELECOMM_SERVICE);
-                    return new TelecommManager(ctx.getOuterContext(),
-                            ITelecommService.Stub.asInterface(b));
+                    return new TelecommManager(ctx.getOuterContext());
                 }});
 
         registerService(PHONE_SERVICE, new ServiceFetcher() {
@@ -963,27 +963,42 @@
         return f.delete();
     }
 
+    // Common-path handling of app data dir creation
+    private static File createFilesDirLocked(File file) {
+        if (!file.exists()) {
+            if (!file.mkdirs()) {
+                if (file.exists()) {
+                    // spurious failure; probably racing with another process for this app
+                    return file;
+                }
+                Log.w(TAG, "Unable to create files subdir " + file.getPath());
+                return null;
+            }
+            FileUtils.setPermissions(
+                    file.getPath(),
+                    FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+                    -1, -1);
+        }
+        return file;
+    }
+
     @Override
     public File getFilesDir() {
         synchronized (mSync) {
             if (mFilesDir == null) {
                 mFilesDir = new File(getDataDirFile(), "files");
             }
-            if (!mFilesDir.exists()) {
-                if(!mFilesDir.mkdirs()) {
-                    if (mFilesDir.exists()) {
-                        // spurious failure; probably racing with another process for this app
-                        return mFilesDir;
-                    }
-                    Log.w(TAG, "Unable to create files directory " + mFilesDir.getPath());
-                    return null;
-                }
-                FileUtils.setPermissions(
-                        mFilesDir.getPath(),
-                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-                        -1, -1);
+            return createFilesDirLocked(mFilesDir);
+        }
+    }
+
+    @Override
+    public File getNoBackupFilesDir() {
+        synchronized (mSync) {
+            if (mNoBackupFilesDir == null) {
+                mNoBackupFilesDir = new File(getDataDirFile(), "no_backup");
             }
-            return mFilesDir;
+            return createFilesDirLocked(mNoBackupFilesDir);
         }
     }
 
@@ -1035,22 +1050,8 @@
             if (mCacheDir == null) {
                 mCacheDir = new File(getDataDirFile(), "cache");
             }
-            if (!mCacheDir.exists()) {
-                if(!mCacheDir.mkdirs()) {
-                    if (mCacheDir.exists()) {
-                        // spurious failure; probably racing with another process for this app
-                        return mCacheDir;
-                    }
-                    Log.w(TAG, "Unable to create cache directory " + mCacheDir.getAbsolutePath());
-                    return null;
-                }
-                FileUtils.setPermissions(
-                        mCacheDir.getPath(),
-                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-                        -1, -1);
-            }
+            return createFilesDirLocked(mCacheDir);
         }
-        return mCacheDir;
     }
 
     @Override
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index f50c93b..1326064 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -282,7 +282,7 @@
         ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
                 mSharedElementNames);
         setTransitionAlpha(mSharedElements, 1);
-        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
+        ArrayList<SharedElementOriginalState> originalImageViewState =
                 setSharedElementState(sharedElementState, sharedElementSnapshots);
         requestLayoutForSharedElements();
 
@@ -294,7 +294,7 @@
             startEnterTransition(transition);
         }
 
-        setOriginalImageViewState(originalImageViewState);
+        setOriginalSharedElementState(mSharedElements, originalImageViewState);
 
         if (mResultReceiver != null) {
             // We can't trust that the view will disappear on the same frame that the shared
diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java
index 7117111..1b2504e 100644
--- a/core/java/android/app/PackageInstallObserver.java
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -25,7 +25,7 @@
         @Override
         public void packageInstalled(String basePackageName, Bundle extras, int returnCode,
                 String msg) {
-            PackageInstallObserver.this.packageInstalled(basePackageName, extras, returnCode);
+            PackageInstallObserver.this.packageInstalled(basePackageName, extras, returnCode, msg);
         }
     };
 
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 886f1a6..e2a86e8 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -247,12 +247,40 @@
             throws IOException;
 
     /**
-     * The default implementation backs up the entirety of the application's "owned"
-     * file system trees to the output.
+     * The application is having its entire file system contents backed up.  {@code data}
+     * points to the backup destination, and the app has the opportunity to choose which
+     * files are to be stored.  To commit a file as part of the backup, call the
+     * {@link #fullBackupFile(File, FullBackupDataOutput)} helper method.  After all file
+     * data is written to the output, the agent returns from this method and the backup
+     * operation concludes.
+     *
+     * <p>Certain parts of the app's data are never backed up even if the app explicitly
+     * sends them to the output:
+     *
+     * <ul>
+     * <li>The contents of the {@link #getCacheDir()} directory</li>
+     * <li>The contents of the {@link #getNoBackupFilesDir()} directory</li>
+     * <li>The contents of the app's shared library directory</li>
+     * </ul>
+     *
+     * <p>The default implementation of this method backs up the entirety of the
+     * application's "owned" file system trees to the output other than the few exceptions
+     * listed above.  Apps only need to override this method if they need to impose special
+     * limitations on which files are being stored beyond the control that
+     * {@link #getNoBackupFilesDir()} offers.
+     *
+     * @param data A structured wrapper pointing to the backup destination.
+     * @throws IOException
+     *
+     * @see Context#getNoBackupFilesDir()
+     * @see #fullBackupFile(File, FullBackupDataOutput)
+     * @see #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long)
      */
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
         ApplicationInfo appInfo = getApplicationInfo();
 
+        // Note that we don't need to think about the no_backup dir because it's outside
+        // all of the ones we will be traversing
         String rootDir = new File(appInfo.dataDir).getCanonicalPath();
         String filesDir = getFilesDir().getCanonicalPath();
         String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
@@ -311,6 +339,10 @@
      * to place it with the proper location and permissions on the device where the
      * data is restored.
      *
+     * <p class="note">It is safe to explicitly back up files underneath your application's
+     * {@link #getNoBackupFilesDir()} directory, and they will be restored to that
+     * location correctly.
+     *
      * @param file The file to be backed up.  The file must exist and be readable by
      *     the caller.
      * @param output The destination to which the backed-up file data will be sent.
@@ -319,6 +351,7 @@
         // Look up where all of our various well-defined dir trees live on this device
         String mainDir;
         String filesDir;
+        String nbFilesDir;
         String dbDir;
         String spDir;
         String cacheDir;
@@ -331,6 +364,7 @@
         try {
             mainDir = new File(appInfo.dataDir).getCanonicalPath();
             filesDir = getFilesDir().getCanonicalPath();
+            nbFilesDir = getNoBackupFilesDir().getCanonicalPath();
             dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
             spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
             cacheDir = getCacheDir().getCanonicalPath();
@@ -354,8 +388,10 @@
             return;
         }
 
-        if (filePath.startsWith(cacheDir) || filePath.startsWith(libDir)) {
-            Log.w(TAG, "lib and cache files are not backed up");
+        if (filePath.startsWith(cacheDir)
+                || filePath.startsWith(libDir)
+                || filePath.startsWith(nbFilesDir)) {
+            Log.w(TAG, "lib, cache, and no_backup files are not backed up");
             return;
         }
 
@@ -508,6 +544,8 @@
                     mode = -1;  // < 0 is a token to skip attempting a chmod()
                 }
             }
+        } else if (domain.equals(FullBackup.NO_BACKUP_TREE_TOKEN)) {
+            basePath = getNoBackupFilesDir().getCanonicalPath();
         } else {
             // Not a supported location
             Log.i(TAG, "Unrecognized domain " + domain);
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 6ebb6c4..e5b47c6 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -40,6 +40,7 @@
     public static final String OBB_TREE_TOKEN = "obb";
     public static final String ROOT_TREE_TOKEN = "r";
     public static final String DATA_TREE_TOKEN = "f";
+    public static final String NO_BACKUP_TREE_TOKEN = "nb";
     public static final String DATABASE_TREE_TOKEN = "db";
     public static final String SHAREDPREFS_TREE_TOKEN = "sp";
     public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 535aaa1..a52cbdd 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -647,6 +647,26 @@
     public abstract File getFilesDir();
 
     /**
+     * Returns the absolute path to the directory on the filesystem similar to
+     * {@link #getFilesDir()}.  The difference is that files placed under this
+     * directory will be excluded from automatic backup to remote storage.  See
+     * {@link android.app.backup.BackupAgent BackupAgent} for a full discussion
+     * of the automatic backup mechanism in Android.
+     *
+     * <p>No permissions are required to read or write to the returned path, since this
+     * path is internal storage.
+     *
+     * @return The path of the directory holding application files that will not be
+     *         automatically backed up to remote storage.
+     *
+     * @see #openFileOutput
+     * @see #getFileStreamPath
+     * @see #getDir
+     * @see android.app.backup.BackupAgent
+     */
+    public abstract File getNoBackupFilesDir();
+
+    /**
      * Returns the absolute path to the directory on the primary external filesystem
      * (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
      * Environment.getExternalStorageDirectory()}) where the application can
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index dbf9122..13eed07 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -200,7 +200,12 @@
     public File getFilesDir() {
         return mBase.getFilesDir();
     }
-    
+
+    @Override
+    public File getNoBackupFilesDir() {
+        return mBase.getNoBackupFilesDir();
+    }
+
     @Override
     public File getExternalFilesDir(String type) {
         return mBase.getExternalFilesDir(type);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 58d3526..3a98f5d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -429,4 +429,9 @@
 
     boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
     boolean getBlockUninstallForUser(String packageName, int userId);
+
+    IBinder getKeySetByAlias(String packageName, String alias);
+    IBinder getSigningKeySet(String packageName);
+    boolean isPackageSignedByKeySet(String packageName, IBinder ks);
+    boolean isPackageSignedByKeySetExactly(String packageName, IBinder ks);
 }
diff --git a/core/java/android/content/pm/KeySet.java b/core/java/android/content/pm/KeySet.java
index 0ef09a4..fcdaa18 100644
--- a/core/java/android/content/pm/KeySet.java
+++ b/core/java/android/content/pm/KeySet.java
@@ -16,19 +16,36 @@
 
 package android.content.pm;
 
-import android.os.Binder;
+import android.os.IBinder;
 
-/** @hide */
+/**
+ * Represents a {@code KeySet} that has been declared in the AndroidManifest.xml
+ * file for the application.  A {@code KeySet} can be used explicitly to
+ * represent a trust relationship with other applications on the device.
+ */
 public class KeySet {
 
-    private Binder token;
+    private IBinder token;
 
     /** @hide */
-    public KeySet(Binder token) {
+    public KeySet(IBinder token) {
+        if (token == null) {
+            throw new NullPointerException("null value for KeySet IBinder token");
+        }
         this.token = token;
     }
 
-    Binder getToken() {
+    /** @hide */
+    public IBinder getToken() {
         return token;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof KeySet) {
+            KeySet ks = (KeySet) o;
+            return token == ks.token;
+        }
+        return false;
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 03d4701..376369a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1167,6 +1167,22 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device includes a relative humidity sensor.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY =
+            "android.hardware.sensor.relative_humidity";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device includes an ambient temperature sensor.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SENSOR_AMBIENT_TEMPERATURE =
+            "android.hardware.sensor.ambient_temperature";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a telephony radio with data
      * communication support.
      */
@@ -3602,6 +3618,33 @@
     public abstract boolean isSafeMode();
 
     /**
+     * Return the {@link KeySet} associated with the String alias for this
+     * application.
+     *
+     * @param alias The alias for a given {@link KeySet} as defined in the
+     *        application's AndroidManifest.xml.
+     */
+    public abstract KeySet getKeySetByAlias(String packageName, String alias);
+
+    /** Return the signing {@link KeySet} for this application. */
+    public abstract KeySet getSigningKeySet(String packageName);
+
+    /**
+     * Return whether the package denoted by packageName has been signed by all
+     * of the keys specified by the {@link KeySet} ks.  This will return true if
+     * the package has been signed by additional keys (a superset) as well.
+     * Compare to {@link #isSignedByExactly(String packageName, KeySet ks)}.
+     */
+    public abstract boolean isSignedBy(String packageName, KeySet ks);
+
+    /**
+     * Return whether the package denoted by packageName has been signed by all
+     * of, and only, the keys specified by the {@link KeySet} ks. Compare to
+     * {@link #isSignedBy(String packageName, KeySet ks)}.
+     */
+    public abstract boolean isSignedByExactly(String packageName, KeySet ks);
+
+    /**
      * Attempts to move package resources from internal to external media or vice versa.
      * Since this may take a little while, the result will
      * be posted back to the given observer.   This call may fail if the calling context
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index e9793c4..5f29e5c 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2.legacy;
 
 import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
 import android.hardware.Camera;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
@@ -463,6 +464,24 @@
         return ids.contains(id);
     }
 
+    static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)
+            throws BufferQueueAbandonedException {
+        checkNotNull(surface);
+        LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing,
+                sensorOrientation));
+    }
+
+    static Size getTextureSize(SurfaceTexture surfaceTexture)
+            throws BufferQueueAbandonedException {
+        checkNotNull(surfaceTexture);
+
+        int[] dimens = new int[2];
+        LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture,
+                /*out*/dimens));
+
+        return new Size(dimens[0], dimens[1]);
+    }
+
     private static native int nativeDetectSurfaceType(Surface surface);
 
     private static native int nativeDetectSurfaceDimens(Surface surface,
@@ -479,4 +498,11 @@
     private static native int nativeSetSurfaceDimens(Surface surface, int width, int height);
 
     private static native long nativeGetSurfaceId(Surface surface);
+
+    private static native int nativeSetSurfaceOrientation(Surface surface, int facing,
+                                                             int sensorOrientation);
+
+    private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
+            /*out*/int[/*2*/] dimens);
+
 }
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index e6d84c5..7d1be3b 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -292,10 +292,13 @@
         mInFlightPreview = null;
         mInFlightJpeg = null;
 
+        int facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING);
+        int orientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
         if (outputs != null) {
             for (Surface s : outputs) {
                 try {
                     int format = LegacyCameraDevice.detectSurfaceType(s);
+                    LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation);
                     switch (format) {
                         case CameraMetadataNative.NATIVE_JPEG_FORMAT:
                             mCallbackOutputs.add(s);
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index daa64c0..fdf9ba0 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -1,18 +1,18 @@
 /*
-* Copyright (C) 2014 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package android.hardware.camera2.legacy;
 
 import android.graphics.ImageFormat;
@@ -98,14 +98,14 @@
      */
     private static final String VERTEX_SHADER =
             "uniform mat4 uMVPMatrix;\n" +
-                    "uniform mat4 uSTMatrix;\n" +
-                    "attribute vec4 aPosition;\n" +
-                    "attribute vec4 aTextureCoord;\n" +
-                    "varying vec2 vTextureCoord;\n" +
-                    "void main() {\n" +
-                    "  gl_Position = uMVPMatrix * aPosition;\n" +
-                    "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
-                    "}\n";
+            "uniform mat4 uSTMatrix;\n" +
+            "attribute vec4 aPosition;\n" +
+            "attribute vec4 aTextureCoord;\n" +
+            "varying vec2 vTextureCoord;\n" +
+            "void main() {\n" +
+            "  gl_Position = uMVPMatrix * aPosition;\n" +
+            "  vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
+            "}\n";
 
     /**
      * This fragment shader simply draws the color in the 2D texture at
@@ -113,12 +113,12 @@
      */
     private static final String FRAGMENT_SHADER =
             "#extension GL_OES_EGL_image_external : require\n" +
-                    "precision mediump float;\n" +
-                    "varying vec2 vTextureCoord;\n" +
-                    "uniform samplerExternalOES sTexture;\n" +
-                    "void main() {\n" +
-                    "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
-                    "}\n";
+            "precision mediump float;\n" +
+            "varying vec2 vTextureCoord;\n" +
+            "uniform samplerExternalOES sTexture;\n" +
+            "void main() {\n" +
+            "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+            "}\n";
 
     private float[] mMVPMatrix = new float[GL_MATRIX_SIZE];
     private float[] mSTMatrix = new float[GL_MATRIX_SIZE];
@@ -189,12 +189,56 @@
         return program;
     }
 
-    private void drawFrame(SurfaceTexture st) {
+    private void drawFrame(SurfaceTexture st, int width, int height) {
         checkGlError("onDrawFrame start");
         st.getTransformMatrix(mSTMatrix);
 
+        Size dimens;
+        try {
+            dimens = LegacyCameraDevice.getTextureSize(st);
+        } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+            // Should never hit this.
+            throw new IllegalStateException("Surface abandoned, skipping drawFrame...", e);
+        }
+
+        Matrix.setIdentityM(mMVPMatrix, /*smOffset*/0);
+
+        float texWidth = dimens.getWidth();
+        float texHeight = dimens.getHeight();
+
+        if (texWidth <= 0 || texHeight <= 0) {
+            throw new IllegalStateException("Illegal intermediate texture with dimension of 0");
+        }
+
+        // Find largest scaling factor from the intermediate texture dimension to the
+        // output surface dimension.  Scaling the intermediate texture by this allows
+        // us to letterbox/pillerbox the output surface into the intermediate texture.
+        float widthRatio = width / texWidth;
+        float heightRatio = height / texHeight;
+        float actual = (widthRatio < heightRatio) ? heightRatio : widthRatio;
+
         if (DEBUG) {
-            GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+            Log.d(TAG, "Scaling factor " + actual + " used for " + width + "x" + height +
+                    " surface, intermediate buffer size is " + texWidth + "x" + texHeight);
+        }
+
+        // Set the viewport height and width to be the scaled intermediate texture dimensions.
+        int viewportW = (int) (actual * texWidth);
+        int viewportH = (int) (actual * texHeight);
+
+        // Set the offset of the viewport so that the output surface is centered in the viewport.
+        float dx = (width - viewportW) / 2f;
+        float dy = (height - viewportH) / 2f;
+
+        if (DEBUG) {
+            Log.d(TAG, "Translation " + dx + "," + dy + " used for " + width + "x" + height +
+                    " surface");
+        }
+
+        GLES20.glViewport((int) dx, (int) dy, viewportW, viewportH);
+
+        if (DEBUG) {
+            GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
             GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
         }
 
@@ -218,7 +262,6 @@
         GLES20.glEnableVertexAttribArray(maTextureHandle);
         checkGlError("glEnableVertexAttribArray maTextureHandle");
 
-        Matrix.setIdentityM(mMVPMatrix, 0);
         GLES20.glUniformMatrix4fv(muMVPMatrixHandle, /*count*/ 1, /*transpose*/ false, mMVPMatrix,
                 /*offset*/ 0);
         GLES20.glUniformMatrix4fv(muSTMatrixHandle, /*count*/ 1, /*transpose*/ false, mSTMatrix,
@@ -589,18 +632,19 @@
         for (EGLSurfaceHolder holder : mSurfaces) {
             if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
                 makeCurrent(holder.eglSurface);
-                drawFrame(mSurfaceTexture);
+                drawFrame(mSurfaceTexture, holder.width, holder.height);
                 swapBuffers(holder.eglSurface);
             }
         }
         for (EGLSurfaceHolder holder : mConversionSurfaces) {
             if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
                 makeCurrent(holder.eglSurface);
-                drawFrame(mSurfaceTexture);
+                drawFrame(mSurfaceTexture, holder.width, holder.height);
                 mPBufferPixels.clear();
-                GLES20.glReadPixels(/*x*/ 0, /*y*/ 0, holder.width, holder.height, GLES20.GL_RGBA,
-                        GLES20.GL_UNSIGNED_BYTE, mPBufferPixels);
+                GLES20.glReadPixels(/*x*/ 0, /*y*/ 0, holder.width, holder.height,
+                        GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mPBufferPixels);
                 checkGlError("glReadPixels");
+
                 try {
                     int format = LegacyCameraDevice.detectSurfaceType(holder.surface);
                     LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(),
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 1557ab0..c5aee7b 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -230,7 +230,7 @@
      *
      * @see #EXTRA_PRINT_JOB_INFO
      */
-    public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.PRINTER_INFO";
+    public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
 
     private Handler mHandler;
 
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 6787fd0..d71ad03 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -188,6 +188,12 @@
          */
         public static final String MIME_TYPE = "mime_type";
         /**
+         * The transcription of the voicemail entry. This will only be populated if the voicemail
+         * entry has a valid transcription.
+         * <P>Type: TEXT</P>
+         */
+        public static final String TRANSCRIPTION = "transcription";
+        /**
          * Path to the media content file. Internal only field.
          * @hide
          */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7fab808..b554548 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -461,6 +461,11 @@
                     }
                 }
 
+                // Compute surface insets required to draw at specified Z value.
+                // TODO: Use real shadow insets for a constant max Z.
+                final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+                attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+
                 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
                 mTranslator = compatibilityInfo.getTranslator();
                 mDisplayAdjustments.setActivityToken(attrs.token);
@@ -1713,8 +1718,8 @@
                 if (hwInitialized ||
                         mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
                         mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
-                    final Rect shadowInsets = params != null ? params.shadowInsets : null;
-                    mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight, shadowInsets);
+                    final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
+                    mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight, surfaceInsets);
                     if (!hwInitialized) {
                         mAttachInfo.mHardwareRenderer.invalidate(mSurface);
                         mFullRedrawNeeded = true;
@@ -2371,7 +2376,7 @@
         }
 
         final WindowManager.LayoutParams params = mWindowAttributes;
-        final Rect surfaceInsets = params != null ? params.shadowInsets : null;
+        final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
         boolean animating = mScroller != null && mScroller.computeScrollOffset();
         final int curScrollY;
         if (animating) {
@@ -3155,7 +3160,7 @@
                             mFullRedrawNeeded = true;
                             try {
                                 final WindowManager.LayoutParams lp = mWindowAttributes;
-                                final Rect surfaceInsets = lp != null ? lp.shadowInsets : null;
+                                final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
                                         mWidth, mHeight, mSurface, surfaceInsets);
                             } catch (OutOfResourcesException e) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index aa71ed8..c169d35 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -23,6 +23,8 @@
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -157,7 +159,7 @@
     private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";
 
     private final Context mContext;
-    
+
     private TypedArray mWindowStyle;
     private Callback mCallback;
     private OnWindowDismissedCallback mOnWindowDismissedCallback;
@@ -181,7 +183,7 @@
     private int mDefaultWindowFormat = PixelFormat.OPAQUE;
 
     private boolean mHasSoftInputMode = false;
-    
+
     private boolean mDestroyed;
 
     // The current window attributes.
@@ -227,7 +229,7 @@
          * @return boolean Return true if this event was consumed.
          */
         public boolean dispatchTouchEvent(MotionEvent event);
-        
+
         /**
          * Called to process trackball events.  At the very least your
          * implementation must call
@@ -313,14 +315,14 @@
          * Called when a panel's menu is opened by the user. This may also be
          * called when the menu is changing from one type to another (for
          * example, from the icon menu to the expanded menu).
-         * 
+         *
          * @param featureId The panel that the menu is in.
          * @param menu The menu that is opened.
          * @return Return true to allow the menu to open, or false to prevent
          *         the menu from opening.
          */
         public boolean onMenuOpened(int featureId, Menu menu);
-        
+
         /**
          * Called when a panel's menu item has been selected by the user.
          *
@@ -364,31 +366,31 @@
          * for more information.
          */
         public void onAttachedToWindow();
-        
+
         /**
          * Called when the window has been attached to the window manager.
          * See {@link View#onDetachedFromWindow() View.onDetachedFromWindow()}
          * for more information.
          */
         public void onDetachedFromWindow();
-        
+
         /**
          * Called when a panel is being closed.  If another logical subsequent
          * panel is being opened (and this panel is being closed to make room for the subsequent
          * panel), this method will NOT be called.
-         * 
+         *
          * @param featureId The panel that is being displayed.
          * @param menu If onCreatePanelView() returned null, this is the Menu
          *            being displayed in the panel.
          */
         public void onPanelClosed(int featureId, Menu menu);
-        
+
         /**
          * Called when the user signals the desire to start a search.
-         * 
+         *
          * @return true if search launched, false if activity refuses (blocks)
-         * 
-         * @see android.app.Activity#onSearchRequested() 
+         *
+         * @see android.app.Activity#onSearchRequested()
          */
         public boolean onSearchRequested();
 
@@ -457,7 +459,7 @@
             return mWindowStyle;
         }
     }
-    
+
     /**
      * Set the container for this window.  If not set, the DecorWindow
      * operates as a top-level window; otherwise, it negotiates with the
@@ -488,7 +490,7 @@
     public final boolean hasChildren() {
         return mHasChildren;
     }
-    
+
     /** @hide */
     public final void destroy() {
         mDestroyed = true;
@@ -622,14 +624,14 @@
      * callback will be used to tell you about state changes to the surface.
      */
     public abstract void takeSurface(SurfaceHolder.Callback2 callback);
-    
+
     /**
      * Take ownership of this window's InputQueue.  The window will no
      * longer read and dispatch input events from the queue; it is your
      * responsibility to do so.
      */
     public abstract void takeInputQueue(InputQueue.Callback callback);
-    
+
     /**
      * Return whether this window is being displayed with a floating style
      * (based on the {@link android.R.attr#windowIsFloating} attribute in
@@ -740,7 +742,7 @@
         }
         dispatchWindowAttributesChanged(attrs);
     }
-    
+
     /**
      * Convenience function to set the flag bits as specified in flags, as
      * per {@link #setFlags}.
@@ -756,7 +758,7 @@
     public void addPrivateFlags(int flags) {
         setPrivateFlags(flags, flags);
     }
-    
+
     /**
      * Convenience function to clear the flag bits as specified in flags, as
      * per {@link #setFlags}.
@@ -772,7 +774,7 @@
      * Set the flags of the window, as per the
      * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
      * flags.
-     * 
+     *
      * <p>Note that some flags must be set before the window decoration is
      * created (by the first call to
      * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)} or
@@ -859,20 +861,20 @@
     protected final int getForcedWindowFlags() {
         return mForcedWindowFlags;
     }
-    
+
     /**
      * Has the app specified their own soft input mode?
      */
     protected final boolean hasSoftInputMode() {
         return mHasSoftInputMode;
     }
-    
+
     /** @hide */
     public void setCloseOnTouchOutside(boolean close) {
         mCloseOnTouchOutside = close;
         mSetCloseOnTouchOutside = true;
     }
-    
+
     /** @hide */
     public void setCloseOnTouchOutsideIfNotSet(boolean close) {
         if (!mSetCloseOnTouchOutside) {
@@ -880,10 +882,10 @@
             mSetCloseOnTouchOutside = true;
         }
     }
-    
+
     /** @hide */
     public abstract void alwaysReadCloseOnTouchAttr();
-    
+
     /** @hide */
     public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
         if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
@@ -892,7 +894,7 @@
         }
         return false;
     }
-    
+
     private boolean isOutOfBounds(Context context, MotionEvent event) {
         final int x = (int) event.getX();
         final int y = (int) event.getY();
@@ -902,7 +904,7 @@
                 || (x > (decorView.getWidth()+slop))
                 || (y > (decorView.getHeight()+slop));
     }
-    
+
     /**
      * Enable extended screen features.  This must be called before
      * setContentView().  May be called as many times as desired as long as it
@@ -989,7 +991,7 @@
      * of the window that can not, from this point forward, be changed: the
      * features that have been requested with {@link #requestFeature(int)},
      * and certain window flags as described in {@link #setFlags(int, int)}.
-     * 
+     *
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
      */
@@ -1037,7 +1039,7 @@
     public abstract void togglePanel(int featureId, KeyEvent event);
 
     public abstract void invalidatePanelMenu(int featureId);
-    
+
     public abstract boolean performPanelShortcut(int featureId,
                                                  int keyCode,
                                                  KeyEvent event,
@@ -1052,17 +1054,17 @@
 
     /**
      * Should be called when the configuration is changed.
-     * 
+     *
      * @param newConfig The new configuration.
      */
     public abstract void onConfigurationChanged(Configuration newConfig);
-    
+
     /**
      * Change the background of this window to a Drawable resource. Setting the
      * background to null will make the window be opaque. To make the window
      * transparent, you can use an empty drawable (for instance a ColorDrawable
      * with the color 0 or the system drawable android:drawable/empty.)
-     * 
+     *
      * @param resid The resource identifier of a drawable resource which will be
      *              installed as the new background.
      */
@@ -1173,7 +1175,7 @@
      *
      */
     public abstract boolean superDispatchTouchEvent(MotionEvent event);
-    
+
     /**
      * Used by custom windows, such as Dialog, to pass the trackball event
      * further down the view hierarchy. Application developers should
@@ -1181,7 +1183,7 @@
      *
      */
     public abstract boolean superDispatchTrackballEvent(MotionEvent event);
-    
+
     /**
      * Used by custom windows, such as Dialog, to pass the generic motion event
      * further down the view hierarchy. Application developers should
@@ -1194,11 +1196,11 @@
      * Retrieve the top-level window decor view (containing the standard
      * window frame/decorations and the client's content inside of that), which
      * can be added as a window to the window manager.
-     * 
+     *
      * <p><em>Note that calling this function for the first time "locks in"
      * various window characteristics as described in
      * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.</em></p>
-     * 
+     *
      * @return Returns the top-level window decor view.
      */
     public abstract View getDecorView();
@@ -1206,16 +1208,16 @@
     /**
      * Retrieve the current decor view, but only if it has already been created;
      * otherwise returns null.
-     * 
+     *
      * @return Returns the top-level window decor or null.
      * @see #getDecorView
      */
     public abstract View peekDecorView();
 
     public abstract Bundle saveHierarchyState();
-    
+
     public abstract void restoreHierarchyState(Bundle savedInstanceState);
-    
+
     protected abstract void onActive();
 
     /**
@@ -1233,10 +1235,10 @@
     {
         return mFeatures;
     }
-    
+
     /**
      * Query for the availability of a certain feature.
-     * 
+     *
      * @param feature The feature ID to check
      * @return true if the feature is enabled, false otherwise.
      */
@@ -1290,9 +1292,9 @@
      * @param event the {@link android.view.KeyEvent} to use to help check.
      */
     public abstract boolean isShortcutKey(int keyCode, KeyEvent event);
-    
+
     /**
-     * @see android.app.Activity#setVolumeControlStream(int) 
+     * @see android.app.Activity#setVolumeControlStream(int)
      */
     public abstract void setVolumeControlStream(int streamType);
 
@@ -1302,6 +1304,19 @@
     public abstract int getVolumeControlStream();
 
     /**
+     * @see android.app.Activity#setMediaController(android.media.session.MediaController)
+     */
+    public void setMediaController(MediaController controller) {
+    }
+
+    /**
+     * @see android.app.Activity#getMediaController()
+     */
+    public MediaController getMediaController() {
+        return null;
+    }
+
+    /**
      * Set extra options that will influence the UI for this window.
      * @param uiOptions Flags specifying extra options for this window.
      */
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c06b5d8..034778f 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1298,7 +1298,7 @@
          *
          * @hide
          */
-        public Rect shadowInsets = new Rect();
+        public Rect surfaceInsets = new Rect();
     
         /**
          * The desired bitmap format.  May be one of the constants in
@@ -1580,10 +1580,10 @@
             out.writeInt(hasSystemUiListeners ? 1 : 0);
             out.writeInt(inputFeatures);
             out.writeLong(userActivityTimeout);
-            out.writeInt(shadowInsets.left);
-            out.writeInt(shadowInsets.top);
-            out.writeInt(shadowInsets.right);
-            out.writeInt(shadowInsets.bottom);
+            out.writeInt(surfaceInsets.left);
+            out.writeInt(surfaceInsets.top);
+            out.writeInt(surfaceInsets.right);
+            out.writeInt(surfaceInsets.bottom);
         }
         
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1626,7 +1626,10 @@
             hasSystemUiListeners = in.readInt() != 0;
             inputFeatures = in.readInt();
             userActivityTimeout = in.readLong();
-            shadowInsets.set(in.readInt(), in.readInt(), in.readInt(), in.readInt());
+            surfaceInsets.left = in.readInt();
+            surfaceInsets.top = in.readInt();
+            surfaceInsets.right = in.readInt();
+            surfaceInsets.bottom = in.readInt();
         }
     
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1658,7 +1661,7 @@
         /** {@hide} */
         public static final int TRANSLUCENT_FLAGS_CHANGED = 1<<19;
         /** {@hide} */
-        public static final int SHADOW_INSETS_CHANGED = 1<<20;
+        public static final int SURFACE_INSETS_CHANGED = 1<<20;
         /** {@hide} */
         public static final int EVERYTHING_CHANGED = 0xffffffff;
 
@@ -1794,9 +1797,9 @@
                 changes |= USER_ACTIVITY_TIMEOUT_CHANGED;
             }
 
-            if (!shadowInsets.equals(o.shadowInsets)) {
-                shadowInsets.set(o.shadowInsets);
-                changes |= SHADOW_INSETS_CHANGED;
+            if (!surfaceInsets.equals(o.surfaceInsets)) {
+                surfaceInsets.set(o.surfaceInsets);
+                changes |= SURFACE_INSETS_CHANGED;
             }
 
             return changes;
@@ -1898,8 +1901,8 @@
             if (userActivityTimeout >= 0) {
                 sb.append(" userActivityTimeout=").append(userActivityTimeout);
             }
-            if (!shadowInsets.equals(Insets.NONE)) {
-                sb.append(" shadowInsets=").append(shadowInsets);
+            if (!surfaceInsets.equals(Insets.NONE)) {
+                sb.append(" surfaceInsets=").append(surfaceInsets);
             }
             sb.append('}');
             return sb.toString();
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 9701c6f..aa0b94f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -36,7 +36,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.LongSparseArray;
-import android.util.MathUtils;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.StateSet;
@@ -61,8 +60,6 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.inputmethod.BaseInputConnection;
@@ -7269,290 +7266,4 @@
             }
         }
     }
-
-    /**
-     * Abstract position scroller that handles sub-position scrolling but has no
-     * understanding of layout.
-     */
-    abstract class AbsSubPositionScroller extends AbsPositionScroller {
-        private static final int DURATION_AUTO = -1;
-
-        private static final int DURATION_AUTO_MIN = 100;
-        private static final int DURATION_AUTO_MAX = 500;
-
-        private final SubScroller mSubScroller = new SubScroller();
-
-        /**
-         * The target offset in pixels between the top of the list and the top
-         * of the target position.
-         */
-        private int mOffset;
-
-        /**
-         * Scroll the minimum amount to get the target view entirely on-screen.
-         */
-        private void scrollToPosition(final int targetPosition, final boolean useOffset,
-                final int offset, final int boundPosition, final int duration) {
-            stop();
-
-            if (mDataChanged) {
-                // Wait until we're back in a stable state to try this.
-                mPositionScrollAfterLayout = new Runnable() {
-                    @Override
-                    public void run() {
-                        scrollToPosition(
-                                targetPosition, useOffset, offset, boundPosition, duration);
-                    }
-                };
-                return;
-            }
-
-            if (mAdapter == null) {
-                // Can't scroll anywhere without an adapter.
-                return;
-            }
-
-            final int itemCount = getCount();
-            final int clampedPosition = MathUtils.constrain(targetPosition, 0, itemCount - 1);
-            final int clampedBoundPosition = MathUtils.constrain(boundPosition, -1, itemCount - 1);
-            final int firstPosition = getFirstVisiblePosition();
-            final int lastPosition = firstPosition + getChildCount();
-            final int targetRow = getRowForPosition(clampedPosition);
-            final int firstRow = getRowForPosition(firstPosition);
-            final int lastRow = getRowForPosition(lastPosition);
-            if (useOffset || targetRow <= firstRow) {
-                // Offset so the target row is top-aligned.
-                mOffset = offset;
-            } else if (targetRow >= lastRow - 1) {
-                // Offset so the target row is bottom-aligned.
-                final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
-                mOffset = getHeightForPosition(clampedPosition) - listHeight;
-            } else {
-                // Don't scroll, target is entirely on-screen.
-                return;
-            }
-
-            float endSubRow = targetRow;
-            if (clampedBoundPosition != INVALID_POSITION) {
-                final int boundRow = getRowForPosition(clampedBoundPosition);
-                if (boundRow >= firstRow && boundRow < lastRow && boundRow != targetRow) {
-                    endSubRow = computeBoundSubRow(targetRow, boundRow);
-                }
-            }
-
-            final View firstChild = getChildAt(0);
-            if (firstChild == null) {
-                return;
-            }
-
-            final int firstChildHeight = firstChild.getHeight();
-            final float startOffsetRatio;
-            if (firstChildHeight == 0) {
-                startOffsetRatio = 0;
-            } else {
-                startOffsetRatio = -firstChild.getTop() / (float) firstChildHeight;
-            }
-
-            final float startSubRow = MathUtils.constrain(
-                    firstRow + startOffsetRatio, 0, getCount());
-            if (startSubRow == endSubRow && mOffset == 0) {
-                // Don't scroll, target is already in position.
-                return;
-            }
-
-            final int durationMillis;
-            if (duration == DURATION_AUTO) {
-                final float subRowDelta = Math.abs(startSubRow - endSubRow);
-                durationMillis = (int) MathUtils.lerp(
-                        DURATION_AUTO_MIN, DURATION_AUTO_MAX, subRowDelta / getCount());
-            } else {
-                durationMillis = duration;
-            }
-
-            mSubScroller.startScroll(startSubRow, endSubRow, durationMillis);
-
-            postOnAnimation(mAnimationFrame);
-        }
-
-        /**
-         * Given a target row and offset, computes the sub-row position that
-         * aligns with the top of the list. If the offset is negative, the
-         * resulting sub-row will be smaller than the target row.
-         */
-        private float resolveOffset(int targetRow, int offset) {
-            // Compute the target sub-row position by finding the actual row
-            // indicated by the target and offset.
-            int remainingOffset = offset;
-            int targetHeight = getHeightForRow(targetRow);
-            if (offset < 0) {
-                // Subtract row heights until we find the right row.
-                while (targetRow > 0 && remainingOffset < 0) {
-                    remainingOffset += targetHeight;
-                    targetRow--;
-                    targetHeight = getHeightForRow(targetRow);
-                }
-            } else if (offset > 0) {
-                // Add row heights until we find the right row.
-                while (targetRow < getCount() - 1 && remainingOffset > targetHeight) {
-                    remainingOffset -= targetHeight;
-                    targetRow++;
-                    targetHeight = getHeightForRow(targetRow);
-                }
-            }
-
-            final float targetOffsetRatio;
-            if (remainingOffset < 0 || targetHeight == 0) {
-                targetOffsetRatio = 0;
-            } else {
-                targetOffsetRatio = remainingOffset / (float) targetHeight;
-            }
-
-            return targetRow + targetOffsetRatio;
-        }
-
-        private float computeBoundSubRow(int targetRow, int boundRow) {
-            final float targetSubRow = resolveOffset(targetRow, mOffset);
-            mOffset = 0;
-
-            // The target row is below the bound row, so the end position would
-            // push the bound position above the list. Abort!
-            if (targetSubRow >= boundRow) {
-                return boundRow;
-            }
-
-            // Compute the closest possible sub-position that wouldn't push the
-            // bound position's view further below the list.
-            final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
-            final int boundHeight = getHeightForRow(boundRow);
-            final float boundSubRow = resolveOffset(boundRow, -listHeight + boundHeight);
-
-            return Math.max(boundSubRow, targetSubRow);
-        }
-
-        @Override
-        public void start(int position) {
-            scrollToPosition(position, false, 0, INVALID_POSITION, DURATION_AUTO);
-        }
-
-        @Override
-        public void start(int position, int boundPosition) {
-            scrollToPosition(position, false, 0, boundPosition, DURATION_AUTO);
-        }
-
-        @Override
-        public void startWithOffset(int position, int offset) {
-            scrollToPosition(position, true, offset, INVALID_POSITION, DURATION_AUTO);
-        }
-
-        @Override
-        public void startWithOffset(int position, int offset, int duration) {
-            scrollToPosition(position, true, offset, INVALID_POSITION, duration);
-        }
-
-        @Override
-        public void stop() {
-            removeCallbacks(mAnimationFrame);
-        }
-
-        /**
-         * Returns the height of a row, which is computed as the maximum height of
-         * the items in the row.
-         *
-         * @param row the row index
-         * @return row height in pixels
-         */
-        public abstract int getHeightForRow(int row);
-
-        /**
-         * Returns the row for the specified item position.
-         *
-         * @param position the item position
-         * @return the row index
-         */
-        public abstract int getRowForPosition(int position);
-
-        /**
-         * Returns the first item position within the specified row.
-         *
-         * @param row the row
-         * @return the position of the first item in the row
-         */
-        public abstract int getFirstPositionForRow(int row);
-
-        private void onAnimationFrame() {
-            final boolean shouldPost = mSubScroller.computePosition();
-            final float subRow = mSubScroller.getPosition();
-
-            final int row = (int) subRow;
-            final int position = getFirstPositionForRow(row);
-            if (position >= getCount()) {
-                // Invalid position, abort scrolling.
-                return;
-            }
-
-            final int rowHeight = getHeightForRow(row);
-            final int offset = (int) (rowHeight * (subRow - row));
-            final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue());
-            setSelectionFromTop(position, -offset - addOffset);
-
-            if (shouldPost) {
-                postOnAnimation(mAnimationFrame);
-            }
-        }
-
-        private Runnable mAnimationFrame = new Runnable() {
-            @Override
-            public void run() {
-                onAnimationFrame();
-            }
-        };
-    }
-
-    /**
-     * Scroller capable of returning floating point positions.
-     */
-    static class SubScroller {
-        private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator();
-
-        private float mStartPosition;
-        private float mEndPosition;
-        private long mStartTime;
-        private long mDuration;
-
-        private float mPosition;
-        private float mInterpolatedValue;
-
-        public void startScroll(float startPosition, float endPosition, int duration) {
-            mStartPosition = startPosition;
-            mEndPosition = endPosition;
-            mDuration = duration;
-
-            mStartTime = AnimationUtils.currentAnimationTimeMillis();
-            mPosition = startPosition;
-            mInterpolatedValue = 0;
-        }
-
-        public boolean computePosition() {
-            final long elapsed = AnimationUtils.currentAnimationTimeMillis() - mStartTime;
-            final float value;
-            if (mDuration <= 0) {
-                value = 1;
-            } else {
-                value = MathUtils.constrain(elapsed / (float) mDuration, 0, 1);
-            }
-
-            mInterpolatedValue = INTERPOLATOR.getInterpolation(value);
-            mPosition = (mEndPosition - mStartPosition) * mInterpolatedValue + mStartPosition;
-
-            return elapsed < mDuration;
-        }
-
-        public float getPosition() {
-            return mPosition;
-        }
-
-        public float getInterpolatedValue() {
-            return mInterpolatedValue;
-        }
-    }
 }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 93810b3..33cc66e 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1029,11 +1029,6 @@
     }
 
     @Override
-    AbsPositionScroller createPositionScroller() {
-        return new GridViewPositionScroller();
-    }
-
-    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Sets up mListPadding
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -2392,33 +2387,4 @@
                 column, 1, row, 1, isHeading, isSelected);
         info.setCollectionItemInfo(itemInfo);
     }
-
-    /**
-     * Sub-position scroller that understands the layout of a GridView.
-     */
-    class GridViewPositionScroller extends AbsSubPositionScroller {
-        @Override
-        public int getRowForPosition(int position) {
-            return position / mNumColumns;
-        }
-
-        @Override
-        public int getFirstPositionForRow(int row) {
-            return row * mNumColumns;
-        }
-
-        @Override
-        public int getHeightForRow(int row) {
-            final int firstRowPosition = row * mNumColumns;
-            final int lastRowPosition = Math.min(getCount(), firstRowPosition + mNumColumns);
-            int maxHeight = 0;
-            for (int i = firstRowPosition; i < lastRowPosition; i++) {
-                final int height = getHeightForPosition(i);
-                if (height > maxHeight) {
-                    maxHeight = height;
-                }
-            }
-            return maxHeight;
-        }
-    }
 }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 1baeca8..9db1e05 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3872,11 +3872,6 @@
     }
 
     @Override
-    AbsPositionScroller createPositionScroller() {
-        return new ListViewPositionScroller();
-    }
-
-    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
         event.setClassName(ListView.class.getName());
@@ -3905,24 +3900,4 @@
                 0, 1, position, 1, isHeading, isSelected);
         info.setCollectionItemInfo(itemInfo);
     }
-
-    /**
-     * Sub-position scroller that understands the layout of a ListView.
-     */
-    class ListViewPositionScroller extends AbsSubPositionScroller {
-        @Override
-        public int getRowForPosition(int position) {
-            return position;
-        }
-
-        @Override
-        public int getFirstPositionForRow(int row) {
-            return row;
-        }
-
-        @Override
-        public int getHeightForRow(int row) {
-            return getHeightForPosition(row);
-        }
-    }
 }
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index a35d447..41d3e320 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1096,10 +1096,6 @@
         p.softInputMode = mSoftInputMode;
         p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
 
-        // TODO: Use real shadow insets once that algorithm is finalized.
-        final int shadowInset = (int) Math.ceil(mElevation * 2);
-        p.shadowInsets.set(shadowInset, shadowInset, shadowInset, shadowInset);
-
         return p;
     }
 
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 9621bb2..d2f5b5d 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -19,17 +19,20 @@
 #include <utils/Log.h>
 #include <utils/Errors.h>
 #include <utils/Trace.h>
+#include <camera/CameraUtils.h>
 
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
+#include "android_runtime/android_graphics_SurfaceTexture.h"
 
 #include <gui/Surface.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <ui/GraphicBuffer.h>
 #include <system/window.h>
 #include <hardware/camera3.h>
+#include <system/camera_metadata.h>
 
 #include <stdint.h>
 #include <inttypes.h>
@@ -335,6 +338,25 @@
     return anw;
 }
 
+static sp<ANativeWindow> getNativeWindowFromTexture(JNIEnv* env, jobject surfaceTexture) {
+    sp<ANativeWindow> anw;
+    if (surfaceTexture) {
+        anw = android_SurfaceTexture_getNativeWindow(env, surfaceTexture);
+        if (env->ExceptionCheck()) {
+            return NULL;
+        }
+    } else {
+        jniThrowNullPointerException(env, "surfaceTexture");
+        return NULL;
+    }
+    if (anw == NULL) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                "SurfaceTexture had no valid native window.");
+        return NULL;
+    }
+    return anw;
+}
+
 static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
     sp<Surface> s;
     if (surface) {
@@ -376,6 +398,17 @@
 static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
           jobject surface, jintArray dimens) {
     ALOGV("nativeGetSurfaceDimens");
+
+    if (dimens == NULL) {
+        ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (env->GetArrayLength(dimens) < 2) {
+        ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
     sp<ANativeWindow> anw;
     if ((anw = getNativeWindow(env, surface)) == NULL) {
         ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
@@ -398,6 +431,37 @@
     return NO_ERROR;
 }
 
+static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
+        jobject surfaceTexture, jintArray dimens) {
+    ALOGV("nativeDetectTextureDimens");
+    sp<ANativeWindow> anw;
+    if ((anw = getNativeWindowFromTexture(env, surfaceTexture)) == NULL) {
+        ALOGE("%s: Could not retrieve native window from SurfaceTexture.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int32_t dimenBuf[2];
+    status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
+    if(err != NO_ERROR) {
+        ALOGE("%s: Error while querying SurfaceTexture width %s (%d)", __FUNCTION__,
+                strerror(-err), err);
+        return err;
+    }
+
+    err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
+    if(err != NO_ERROR) {
+        ALOGE("%s: Error while querying SurfaceTexture height %s (%d)", __FUNCTION__,
+                strerror(-err), err);
+        return err;
+    }
+
+    env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
+    if (env->ExceptionCheck()) {
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
+}
+
 static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
         jint width, jint height, jint pixelFormat) {
     ALOGV("nativeConfigureSurface");
@@ -504,6 +568,42 @@
     return reinterpret_cast<jlong>(b.get());
 }
 
+static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject thiz,
+        jobject surface, jint facing, jint orientation) {
+    ALOGV("nativeSetSurfaceOrientation");
+    sp<ANativeWindow> anw;
+    if ((anw = getNativeWindow(env, surface)) == NULL) {
+        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err = NO_ERROR;
+    CameraMetadata staticMetadata;
+
+    int32_t orientVal = static_cast<int32_t>(orientation);
+    uint8_t facingVal = static_cast<uint8_t>(facing);
+    staticMetadata.update(ANDROID_SENSOR_ORIENTATION, &orientVal, 1);
+    staticMetadata.update(ANDROID_LENS_FACING, &facingVal, 1);
+
+    int32_t transform = 0;
+
+    if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != OK) {
+        ALOGE("%s: Invalid rotation transform %s (%d)", __FUNCTION__, strerror(-err),
+                err);
+        return err;
+    }
+
+    ALOGV("%s: Setting buffer sticky transform to %d", __FUNCTION__, transform);
+
+    if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != OK) {
+        ALOGE("%s: Unable to configure surface transform, error %s (%d)", __FUNCTION__,
+                strerror(-err), err);
+        return err;
+    }
+
+    return NO_ERROR;
+}
+
 } // extern "C"
 
 static JNINativeMethod gCameraDeviceMethods[] = {
@@ -528,6 +628,12 @@
     { "nativeGetSurfaceId",
     "(Landroid/view/Surface;)J",
     (void *)LegacyCameraDevice_nativeGetSurfaceId },
+    { "nativeDetectTextureDimens",
+    "(Landroid/graphics/SurfaceTexture;[I)I",
+    (void *)LegacyCameraDevice_nativeDetectTextureDimens },
+    { "nativeSetSurfaceOrientation",
+    "(Landroid/view/Surface;II)I",
+    (void *)LegacyCameraDevice_nativeSetSurfaceOrientation },
 };
 
 // Get all the required offsets in java class and register native functions
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 989b60e..64366e5 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -439,8 +439,11 @@
     if (!is_system_server) {
         int rc = createProcessGroup(uid, getpid());
         if (rc != 0) {
-            ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
-            RuntimeAbort(env);
+            if (rc == -EROFS) {
+                ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
+            } else {
+                ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
+            }
         }
     }
 
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 93acc3f..6a435b2 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -20,13 +20,7 @@
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:background="@drawable/dialog_background_material"
-    android:translationZ="@dimen/floating_window_z"
-    android:layout_marginLeft="@dimen/floating_window_margin_left"
-    android:layout_marginTop="@dimen/floating_window_margin_top"
-    android:layout_marginRight="@dimen/floating_window_margin_right"
-    android:layout_marginBottom="@dimen/floating_window_margin_bottom">
+    android:orientation="vertical">
 
     <LinearLayout android:id="@+id/topPanel"
         android:layout_width="match_parent"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5fdadb7..ed228e4 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1826,6 +1826,9 @@
              Activity Transition. Corresponds to
              {@link android.view.Window#setTransitionBackgroundFadeDuration(long)}. -->
         <attr name="windowTransitionBackgroundFadeDuration" />
+
+        <!-- Elevation to use for the window. -->
+        <attr name="windowElevation" format="dimension" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a0ca06e..fee5c43 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2233,6 +2233,9 @@
   <public type="attr" name="buttonBarNegativeButtonStyle" />
   <public type="attr" name="popupElevation" />
   <public type="attr" name="actionBarPopupTheme" />
+  <public type="attr" name="multiArch" />
+  <public type="attr" name="touchscreenBlocksFocus" />
+  <public type="attr" name="windowElevation" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2509,6 +2512,4 @@
   <!-- A transition that moves views in or out of the scene to or from the left edge when
        a view visibility changes. -->
   <public type="transition" name="slide_left"/>
-  <public type="attr" name="multiArch" />
-  <public type="attr" name="touchscreenBlocksFocus" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 193d3c0..2ecaa5c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3627,13 +3627,13 @@
     <!-- See SIM_REMOVED_DIALOG.  This is the title of that dialog. -->
     <string name="sim_removed_title">SIM card removed</string>
     <!-- See SIM_REMOVED_DIALOG.  This is the message of that dialog. -->
-    <string name="sim_removed_message">The mobile network will be unavailable until you restart with a valid SIM card inserted.</string>
+    <string name="sim_removed_message">The cellular network will be unavailable until you restart with a valid SIM card inserted.</string>
     <!-- See SIM_REMOVED_DIALOG.  This is the button of that dialog. -->
     <string name="sim_done_button">Done</string>
     <!-- See SIM_ADDED_DIALOG.  This is the title of that dialog. -->
     <string name="sim_added_title">SIM card added</string>
     <!-- See SIM_ADDED_DIALOG.  This is the message of that dialog. -->
-    <string name="sim_added_message">Restart your device to access the mobile network.</string>
+    <string name="sim_added_message">Restart your device to access the cellular network.</string>
     <!-- See SIM_ADDED_DIALOG.  This is the button of that dialog. -->
     <string name="sim_restart_button">Restart</string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 0eceae6..f5d7f5f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -824,15 +824,9 @@
         <item name="textColorLink">?textColorLinkInverse</item>
     </style>
 
-    <style name="TextAppearance.Theme.Dialog" parent="TextAppearance.Theme">
-    </style>
+    <style name="TextAppearance.Theme.Dialog" parent="TextAppearance.Theme" />
 
-    <style name="TextAppearance.Theme.Dialog.AppError">
-        <item name="textColor">#ffffc0c0</item>
-    </style>
-
-    <style name="TextAppearance.Widget">
-    </style>
+    <style name="TextAppearance.Widget" />
 
     <style name="TextAppearance.Widget.Button" parent="TextAppearance.Small.Inverse">
         <item name="textColor">@color/primary_text_light_nodisable</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 6ada975..a519c37 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -820,21 +820,14 @@
     <eat-comment />
 
     <!-- Theme for the dialog shown when an app crashes or ANRs. -->
-    <style name="Theme.Dialog.AppError" parent="Theme.DeviceDefault.Light.Dialog">
-        <item name="windowFrame">@null</item>
-        <item name="windowTitleStyle">@style/DialogWindowTitle</item>
-        <item name="windowBackground">@color/transparent</item>
-        <item name="windowIsFloating">true</item>
-        <item name="windowContentOverlay">@null</item>
+    <style name="Theme.Dialog.AppError" parent="Theme.DeviceDefault.Light.Dialog.Alert">
         <item name="windowContentTransitions">false</item>
-        <item name="textAppearance">@style/TextAppearance.Theme.Dialog.AppError</item>
         <item name="windowCloseOnTouchOutside">false</item>
     </style>
 
     <!-- Special theme for the recent apps dialog, to allow customization
          with overlays. -->
     <style name="Theme.Dialog.RecentApplications" parent="Theme.DeviceDefault.Light.Dialog">
-        <item name="windowFrame">@null</item>
         <item name="windowBackground">@color/transparent</item>
         <item name="windowAnimationStyle">@style/Animation.RecentApplications</item>
         <item name="textColor">@color/secondary_text_nofocus</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 47f3778..efc92d9 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1011,7 +1011,8 @@
     <style name="Theme.Material.Dialog">
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
-        <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
+        <item name="windowBackground">@drawable/dialog_background_material</item>
+        <item name="windowElevation">@dimen/floating_window_z</item>
         <item name="windowIsFloating">true</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
@@ -1077,6 +1078,7 @@
          its pixels. -->
     <style name="Theme.Material.Dialog.NoFrame">
         <item name="windowBackground">@color/transparent</item>
+        <item name="windowElevation">0dp</item>
         <item name="windowAnimationStyle">@null</item>
         <item name="backgroundDimEnabled">false</item>
         <item name="windowIsTranslucent">true</item>
@@ -1085,7 +1087,6 @@
     </style>
 
     <style name="Theme.Material.Dialog.BaseAlert">
-        <item name="windowBackground">@color/transparent</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
         <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
         <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
@@ -1100,6 +1101,7 @@
 
     <style name="Theme.Material.Dialog.BaseTimePicker">
         <item name="windowBackground">@color/transparent</item>
+        <item name="windowElevation">0dp</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
         <item name="windowContentOverlay">@null</item>
     </style>
@@ -1131,7 +1133,8 @@
     <style name="Theme.Material.Light.Dialog">
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
-        <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
+        <item name="windowBackground">@drawable/dialog_background_material</item>
+        <item name="windowElevation">@dimen/floating_window_z</item>
         <item name="windowIsFloating">true</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
@@ -1203,7 +1206,6 @@
     <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.NoActionBar" />
 
     <style name="Theme.Material.Light.Dialog.BaseAlert">
-        <item name="windowBackground">@color/transparent</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
         <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
         <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
@@ -1218,6 +1220,7 @@
 
     <style name="Theme.Material.Light.Dialog.BaseTimePicker">
         <item name="windowBackground">@color/transparent</item>
+        <item name="windowElevation">0dp</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
     </style>
 
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index a2cc40c..b524177 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1257,4 +1257,11 @@
     <instrumentation android:name="android.test.InstrumentationTestRunner"
             android:targetPackage="com.android.frameworks.coretests"
             android:label="Frameworks Core Tests" />
+    <key-sets>
+        <key-set android:name="A" >
+          <public-key android:name="keyA"
+                      android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJoN1Nsgqf0V4C/bbN8wo8O2X/S5D76+5Mb9mlIsHkUTUTbHCNk+LxHIUYLm89YbP9zImrV0bUHLUAZUyoMUCiMCAwEAAQ=="/>
+        </key-set>
+        <upgrade-key-set android:name="A"/>
+    </key-sets>
 </manifest>
diff --git a/core/tests/coretests/apks/keyset/Android.mk b/core/tests/coretests/apks/keyset/Android.mk
index e44ac6c..306dc90 100644
--- a/core/tests/coretests/apks/keyset/Android.mk
+++ b/core/tests/coretests/apks/keyset/Android.mk
@@ -88,4 +88,21 @@
 LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
 LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_B
 LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+#apks signed by platform only
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_splat_api
+LOCAL_CERTIFICATE := platform
+LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+#apks signed by platform and keyset_A
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_splata_api
+LOCAL_CERTIFICATE := platform
+LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
 include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml b/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml
new file mode 100644
index 0000000..4c7e968
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.coretests.keysets_api">
+    <application android:hasCode="false">
+    </application>
+</manifest>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 0244425..3a80309 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.KeySet;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -33,6 +34,7 @@
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -3328,6 +3330,174 @@
     }
 
     /**
+     * The following tests are related to testing KeySets-based API
+     */
+
+    /*
+     * testGetSigningKeySetNull - ensure getSigningKeySet() returns null on null
+     * input and when calling a package other than that which made the call.
+     */
+    public void testGetSigningKeySet() throws Exception {
+        PackageManager pm = getPm();
+        String mPkgName = mContext.getPackageName();
+        String otherPkgName = "com.android.frameworks.coretests.keysets_api";
+        KeySet ks;
+        try {
+            ks = pm.getSigningKeySet(null);
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            ks = pm.getSigningKeySet("keysets.test.bogus.package");
+            assertTrue(false); // should have thrown
+        } catch (IllegalArgumentException e) {
+        }
+        installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+                0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+        try {
+            ks = pm.getSigningKeySet(otherPkgName);
+            assertTrue(false); // should have thrown
+        } catch (SecurityException e) {
+        }
+        cleanUpInstall(otherPkgName);
+        ks = pm.getSigningKeySet(mContext.getPackageName());
+        assertNotNull(ks);
+    }
+
+    /*
+     * testGetKeySetByAlias - same as getSigningKeySet, but for keysets defined
+     * by this package.
+     */
+    public void testGetKeySetByAlias() throws Exception {
+        PackageManager pm = getPm();
+        String mPkgName = mContext.getPackageName();
+        String otherPkgName = "com.android.frameworks.coretests.keysets_api";
+        KeySet ks;
+        try {
+            ks = pm.getKeySetByAlias(null, null);
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            ks = pm.getKeySetByAlias(null, "keysetBogus");
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            ks = pm.getKeySetByAlias("keysets.test.bogus.package", null);
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            ks = pm.getKeySetByAlias("keysets.test.bogus.package", "A");
+            assertTrue(false); // should have thrown
+        } catch(IllegalArgumentException e) {
+        }
+        try {
+            ks = pm.getKeySetByAlias(mPkgName, "keysetBogus");
+            assertTrue(false); // should have thrown
+        } catch(IllegalArgumentException e) {
+        }
+        installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+                0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+        try {
+            ks = pm.getKeySetByAlias(otherPkgName, "A");
+            assertTrue(false); // should have thrown
+        } catch (SecurityException e) {
+        }
+        cleanUpInstall(otherPkgName);
+        ks = pm.getKeySetByAlias(mPkgName, "A");
+        assertNotNull(ks);
+    }
+
+    public void testIsSignedBy() throws Exception {
+        PackageManager pm = getPm();
+        String mPkgName = mContext.getPackageName();
+        String otherPkgName = "com.android.frameworks.coretests.keysets_api";
+        KeySet mSigningKS = pm.getSigningKeySet(mPkgName);
+        KeySet mDefinedKS = pm.getKeySetByAlias(mPkgName, "A");
+
+        try {
+            assertFalse(pm.isSignedBy(null, null));
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            assertFalse(pm.isSignedBy(null, mSigningKS));
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            assertFalse(pm.isSignedBy(mPkgName, null));
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            assertFalse(pm.isSignedBy("keysets.test.bogus.package", mDefinedKS));
+        } catch(IllegalArgumentException e) {
+        }
+        assertFalse(pm.isSignedBy(mPkgName, mDefinedKS));
+        assertFalse(pm.isSignedBy(mPkgName, new KeySet(new Binder())));
+        assertTrue(pm.isSignedBy(mPkgName, mSigningKS));
+
+        installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+                0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+        assertFalse(pm.isSignedBy(otherPkgName, mDefinedKS));
+        assertTrue(pm.isSignedBy(otherPkgName, mSigningKS));
+        cleanUpInstall(otherPkgName);
+
+        installFromRawResource("keysetApi.apk", R.raw.keyset_splata_api,
+                0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+        assertTrue(pm.isSignedBy(otherPkgName, mDefinedKS));
+        assertTrue(pm.isSignedBy(otherPkgName, mSigningKS));
+        cleanUpInstall(otherPkgName);
+    }
+
+    public void testIsSignedByExactly() throws Exception {
+        PackageManager pm = getPm();
+        String mPkgName = mContext.getPackageName();
+        String otherPkgName = "com.android.frameworks.coretests.keysets_api";
+        KeySet mSigningKS = pm.getSigningKeySet(mPkgName);
+        KeySet mDefinedKS = pm.getKeySetByAlias(mPkgName, "A");
+        try {
+            assertFalse(pm.isSignedBy(null, null));
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            assertFalse(pm.isSignedBy(null, mSigningKS));
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            assertFalse(pm.isSignedBy(mPkgName, null));
+            assertTrue(false); // should have thrown
+        } catch (NullPointerException e) {
+        }
+        try {
+            assertFalse(pm.isSignedByExactly("keysets.test.bogus.package", mDefinedKS));
+        } catch(IllegalArgumentException e) {
+        }
+        assertFalse(pm.isSignedByExactly(mPkgName, mDefinedKS));
+        assertFalse(pm.isSignedByExactly(mPkgName, new KeySet(new Binder())));
+        assertTrue(pm.isSignedByExactly(mPkgName, mSigningKS));
+
+        installFromRawResource("keysetApi.apk", R.raw.keyset_splat_api,
+                0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+        assertFalse(pm.isSignedByExactly(otherPkgName, mDefinedKS));
+        assertTrue(pm.isSignedByExactly(otherPkgName, mSigningKS));
+        cleanUpInstall(otherPkgName);
+
+        installFromRawResource("keysetApi.apk", R.raw.keyset_splata_api,
+                0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+        assertFalse(pm.isSignedByExactly(otherPkgName, mDefinedKS));
+        assertFalse(pm.isSignedByExactly(otherPkgName, mSigningKS));
+        cleanUpInstall(otherPkgName);
+    }
+
+
+
+    /**
      * The following tests are related to testing the checkSignatures api.
      */
     private void checkSignatures(int apk1, int apk2, int expMatchResult) throws Exception {
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 1cecef3..b5fc628 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -209,6 +209,7 @@
                     if (drawableRes != 0) {
                         mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable(
                                 drawableRes, theme).mutate();
+                        mAnimatedVectorState.mVectorDrawable.setAllowCaching(false);
                     }
                     a.recycle();
                 } else if (TARGET.equals(tagName)) {
@@ -258,6 +259,7 @@
                 mChangingConfigurations = copy.mChangingConfigurations;
                 // TODO: Make sure the constant state are handled correctly.
                 mVectorDrawable = new VectorDrawable();
+                mVectorDrawable.setAllowCaching(false);
                 mAnimators = new ArrayList<Animator>();
             }
         }
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 8783994..8c907b2 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -18,6 +18,7 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -142,6 +143,10 @@
 
     private boolean mMutated;
 
+    // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise,
+    // caching the bitmap by default is allowed.
+    private boolean mAllowCaching = true;
+
     public VectorDrawable() {
         mVectorState = new VectorDrawableState();
     }
@@ -183,7 +188,23 @@
         final int saveCount = canvas.save();
         final Rect bounds = getBounds();
         canvas.translate(bounds.left, bounds.top);
-        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
+
+        if (!mAllowCaching) {
+            mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
+        } else {
+            Bitmap bitmap = mVectorState.mCachedBitmap;
+            if (bitmap == null || !mVectorState.canReuseCache(bounds.width(),
+                    bounds.height())) {
+                bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
+                        Bitmap.Config.ARGB_8888);
+                Canvas tmpCanvas = new Canvas(bitmap);
+                mVectorState.mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height());
+                mVectorState.mCachedBitmap = bitmap;
+
+                mVectorState.updateCacheStates();
+            }
+            canvas.drawBitmap(bitmap, null, bounds, null);
+        }
         canvas.restoreToCount(saveCount);
     }
 
@@ -444,6 +465,10 @@
         return super.getChangingConfigurations() | mVectorState.mChangingConfigurations;
     }
 
+    void setAllowCaching(boolean allowCaching) {
+        mAllowCaching = allowCaching;
+    }
+
     private static class VectorDrawableState extends ConstantState {
         int[] mThemeAttrs;
         int mChangingConfigurations;
@@ -451,6 +476,12 @@
         ColorStateList mTint;
         Mode mTintMode;
 
+        Bitmap mCachedBitmap;
+        int[] mCachedThemeAttrs;
+        ColorStateList mCachedTint;
+        Mode mCachedTintMode;
+        int mCachedRootAlpha;
+
         // Deep copy for mutate() or implicitly mutate.
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
@@ -462,6 +493,27 @@
             }
         }
 
+        public boolean canReuseCache(int width, int height) {
+            if (mCachedThemeAttrs == mThemeAttrs
+                    && mCachedTint == mTint
+                    && mCachedTintMode == mTintMode
+                    && width == mCachedBitmap.getWidth()
+                    && height == mCachedBitmap.getHeight()
+                    && mCachedRootAlpha == mVPathRenderer.getRootAlpha())  {
+                return true;
+            }
+            return false;
+        }
+
+        public void updateCacheStates() {
+            // Use shallow copy here and shallow comparison in canReuseCache(),
+            // likely hit cache miss more, but practically not much difference.
+            mCachedThemeAttrs = mThemeAttrs;
+            mCachedTint = mTint;
+            mCachedTintMode = mTintMode;
+            mCachedRootAlpha = mVPathRenderer.getRootAlpha();
+        }
+
         public VectorDrawableState() {
             mVPathRenderer = new VPathRenderer();
         }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index eb6bf2c..c65961d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2912,6 +2912,20 @@
     }
 
     /**
+     * Notify audio manager about volume controller visibility changes.
+     * Currently limited to SystemUI.
+     *
+     * @hide
+     */
+    public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
+        try {
+            getService().notifyVolumeControllerVisible(controller, visible);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error notifying about volume controller visibility", e);
+        }
+    }
+
+    /**
      * Only useful for volume controllers.
      * @hide
      */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index b08d631..ab63145 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -61,6 +61,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.Vibrator;
@@ -810,6 +811,9 @@
 
         // Restore the default media button receiver from the system settings
         mMediaFocusControl.restoreMediaButtonReceiver();
+
+        // Load settings for the volume controller
+        mVolumeController.loadSettings(cr);
     }
 
     private int rescaleIndex(int index, int srcStream, int dstStream) {
@@ -851,14 +855,23 @@
         } else {
             streamType = getActiveStreamType(suggestedStreamType);
         }
+        final int resolvedStream = mStreamVolumeAlias[streamType];
 
         // Play sounds on STREAM_RING and STREAM_REMOTE_MUSIC only.
         if ((streamType != STREAM_REMOTE_MUSIC) &&
                 (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
-                (mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)) {
+                resolvedStream != AudioSystem.STREAM_RING) {
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
         }
 
+        // For notifications/ring, show the ui before making any adjustments
+        if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
+            direction = 0;
+            flags &= ~AudioManager.FLAG_PLAY_SOUND;
+            flags &= ~AudioManager.FLAG_VIBRATE;
+            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
+        }
+
         if (streamType == STREAM_REMOTE_MUSIC) {
             // TODO bounce it to MediaSessionService to find an appropriate
             // session
@@ -4955,15 +4968,65 @@
             }
         }
         mVolumeController.setController(controller);
+        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
+    }
+
+    @Override
+    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
+        enforceSelfOrSystemUI("notify about volume controller visibility");
+
+        // return early if the controller is not current
+        if (!mVolumeController.isSameBinder(controller)) {
+            return;
+        }
+
+        mVolumeController.setVisible(visible);
+        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
     }
 
     public static class VolumeController {
         private static final String TAG = "VolumeController";
 
         private IVolumeController mController;
+        private boolean mVisible;
+        private long mNextLongPress;
+        private int mLongPressTimeout;
 
         public void setController(IVolumeController controller) {
             mController = controller;
+            mVisible = false;
+        }
+
+        public void loadSettings(ContentResolver cr) {
+            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
+                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
+        }
+
+        public boolean suppressAdjustment(int resolvedStream, int flags) {
+            boolean suppress = false;
+            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
+                final long now = SystemClock.uptimeMillis();
+                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
+                    // ui will become visible
+                    if (mNextLongPress < now) {
+                        mNextLongPress = now + mLongPressTimeout;
+                    }
+                    suppress = true;
+                } else if (mNextLongPress > 0) {  // in a long-press
+                    if (now > mNextLongPress) {
+                        // long press triggered, no more suppression
+                        mNextLongPress = 0;
+                    } else {
+                        // keep suppressing until the long press triggers
+                        suppress = true;
+                    }
+                }
+            }
+            return suppress;
+        }
+
+        public void setVisible(boolean visible) {
+            mVisible = visible;
         }
 
         public boolean isSameBinder(IVolumeController controller) {
@@ -4980,7 +5043,7 @@
 
         @Override
         public String toString() {
-            return "VolumeController(" + asBinder() + ")";
+            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
         }
 
         public void postDisplaySafeVolumeWarning(int flags) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e112a65..4f7021e 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -195,6 +195,8 @@
 
     void setVolumeController(in IVolumeController controller);
 
+    void notifyVolumeControllerVisible(in IVolumeController controller, boolean visible);
+
     boolean isStreamAffectedByRingerMode(int streamType);
 
     void disableSafeMediaVolume();
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 73bc61a..740a9d3 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -682,9 +682,13 @@
                 // USE_SESSIONS
                 if (mSession != null) {
                     int pbState = PlaybackState.getStateFromRccState(state);
-                    mSessionPlaybackState.setState(pbState, hasPosition ?
-                            mPlaybackPositionMs : PlaybackState.PLAYBACK_POSITION_UNKNOWN,
-                            playbackSpeed);
+                    long position = hasPosition ? mPlaybackPositionMs
+                            : PlaybackState.PLAYBACK_POSITION_UNKNOWN;
+
+                    PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState);
+                    bob.setState(pbState, position, playbackSpeed, SystemClock.elapsedRealtime());
+                    bob.setErrorMessage(null);
+                    mSessionPlaybackState = bob.build();
                     mSession.setPlaybackState(mSessionPlaybackState);
                 }
             }
@@ -745,8 +749,9 @@
 
             // USE_SESSIONS
             if (mSession != null) {
-                mSessionPlaybackState.setActions(PlaybackState
-                        .getActionsFromRccControlFlags(transportControlFlags));
+                PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState);
+                bob.setActions(PlaybackState.getActionsFromRccControlFlags(transportControlFlags));
+                mSessionPlaybackState = bob.build();
                 mSession.setPlaybackState(mSessionPlaybackState);
             }
         }
@@ -946,7 +951,7 @@
     /**
      * Cache for the current playback state using Session APIs.
      */
-    private final PlaybackState mSessionPlaybackState = new PlaybackState();
+    private PlaybackState mSessionPlaybackState = null;
 
     /**
      * Cache for metadata using Session APIs. This is re-initialized in apply().
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 1f5b216..9ea3f26 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -1020,7 +1020,7 @@
                 l.onClientPlaybackStateUpdate(playstate);
             } else {
                 l.onClientPlaybackStateUpdate(playstate, state.getLastPositionUpdateTime(),
-                        state.getPosition(), state.getPlaybackRate());
+                        state.getPosition(), state.getPlaybackSpeed());
             }
             if (state != null) {
                 l.onClientTransportControlUpdate(PlaybackState.getRccControlFlagsFromActions(state
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 5d1a7e0..11f7720 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -202,7 +202,7 @@
                 if (up) {
                     flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
                 } else {
-                    flags = AudioManager.FLAG_SHOW_UI;
+                    flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
                 }
             }
 
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 9ae2436..f7e7176 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -184,41 +184,29 @@
      */
     public final static long PLAYBACK_POSITION_UNKNOWN = -1;
 
-    private int mState;
-    private long mPosition;
-    private long mBufferPosition;
-    private float mRate;
-    private long mActions;
-    private CharSequence mErrorMessage;
-    private long mUpdateTime;
+    private final int mState;
+    private final long mPosition;
+    private final long mBufferPosition;
+    private final float mSpeed;
+    private final long mActions;
+    private final CharSequence mErrorMessage;
+    private final long mUpdateTime;
 
-    /**
-     * Create an empty PlaybackState. At minimum a state and actions should be
-     * set before publishing a PlaybackState.
-     */
-    public PlaybackState() {
-    }
-
-    /**
-     * Create a new PlaybackState from an existing PlaybackState. All fields
-     * will be copied to the new state.
-     *
-     * @param from The PlaybackState to duplicate
-     */
-    public PlaybackState(PlaybackState from) {
-        mState = from.mState;
-        mPosition = from.mPosition;
-        mRate = from.mRate;
-        mUpdateTime = from.mUpdateTime;
-        mBufferPosition = from.mBufferPosition;
-        mActions = from.mActions;
-        mErrorMessage = from.mErrorMessage;
+    private PlaybackState(int state, long position, long updateTime, float speed,
+            long bufferPosition, long actions, CharSequence error) {
+        mState = state;
+        mPosition = position;
+        mSpeed = speed;
+        mUpdateTime = updateTime;
+        mBufferPosition = bufferPosition;
+        mActions = actions;
+        mErrorMessage = error;
     }
 
     private PlaybackState(Parcel in) {
         mState = in.readInt();
         mPosition = in.readLong();
-        mRate = in.readFloat();
+        mSpeed = in.readFloat();
         mUpdateTime = in.readLong();
         mBufferPosition = in.readLong();
         mActions = in.readLong();
@@ -232,7 +220,7 @@
         bob.append("state=").append(mState);
         bob.append(", position=").append(mPosition);
         bob.append(", buffered position=").append(mBufferPosition);
-        bob.append(", rate=").append(mRate);
+        bob.append(", speed=").append(mSpeed);
         bob.append(", updated=").append(mUpdateTime);
         bob.append(", actions=").append(mActions);
         bob.append(", error=").append(mErrorMessage);
@@ -249,7 +237,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mState);
         dest.writeLong(mPosition);
-        dest.writeFloat(mRate);
+        dest.writeFloat(mSpeed);
         dest.writeLong(mUpdateTime);
         dest.writeLong(mBufferPosition);
         dest.writeLong(mActions);
@@ -271,41 +259,6 @@
     public int getState() {
         return mState;
     }
-
-    /**
-     * Set the current state of playback.
-     * <p>
-     * The position must be in ms and indicates the current playback position
-     * within the track. If the position is unknown use
-     * {@link #PLAYBACK_POSITION_UNKNOWN}.
-     * <p>
-     * The rate is a multiple of normal playback and should be 0 when paused and
-     * negative when rewinding. Normal playback rate is 1.0.
-     * <p>
-     * The state must be one of the following:
-     * <ul>
-     * <li> {@link PlaybackState#STATE_NONE}</li>
-     * <li> {@link PlaybackState#STATE_STOPPED}</li>
-     * <li> {@link PlaybackState#STATE_PLAYING}</li>
-     * <li> {@link PlaybackState#STATE_PAUSED}</li>
-     * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
-     * <li> {@link PlaybackState#STATE_REWINDING}</li>
-     * <li> {@link PlaybackState#STATE_BUFFERING}</li>
-     * <li> {@link PlaybackState#STATE_ERROR}</li>
-     * </ul>
-     *
-     * @param state The current state of playback.
-     * @param position The position in the current track in ms.
-     * @param playbackRate The current rate of playback as a multiple of normal
-     *            playback.
-     */
-    public void setState(int state, long position, float playbackRate) {
-        this.mState = state;
-        this.mPosition = position;
-        this.mRate = playbackRate;
-        mUpdateTime = SystemClock.elapsedRealtime();
-    }
-
     /**
      * Get the current playback position in ms.
      */
@@ -323,23 +276,14 @@
     }
 
     /**
-     * Set the current buffer position in ms. This is the farthest playback
-     * point that can be reached from the current position using only buffered
-     * content.
-     */
-    public void setBufferPosition(long bufferPosition) {
-        mBufferPosition = bufferPosition;
-    }
-
-    /**
-     * Get the current playback rate as a multiple of normal playback. This
+     * Get the current playback speed as a multiple of normal playback. This
      * should be negative when rewinding. A value of 1 means normal playback and
      * 0 means paused.
      *
-     * @return The current rate of playback.
+     * @return The current speed of playback.
      */
-    public float getPlaybackRate() {
-        return mRate;
+    public float getPlaybackSpeed() {
+        return mSpeed;
     }
 
     /**
@@ -362,25 +306,6 @@
     }
 
     /**
-     * Set the current capabilities available on this session. This should use a
-     * bitmask of the available capabilities.
-     * <ul>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
-     * <li> {@link PlaybackState#ACTION_REWIND}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY}</li>
-     * <li> {@link PlaybackState#ACTION_PAUSE}</li>
-     * <li> {@link PlaybackState#ACTION_STOP}</li>
-     * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
-     * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
-     * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
-     * </ul>
-     */
-    public void setActions(long capabilities) {
-        mActions = capabilities;
-    }
-
-    /**
      * Get a user readable error message. This should be set when the state is
      * {@link PlaybackState#STATE_ERROR}.
      */
@@ -393,21 +318,12 @@
      * position has never been set this will return 0;
      *
      * @return The last time the position was updated.
-     * @hide
      */
     public long getLastPositionUpdateTime() {
         return mUpdateTime;
     }
 
     /**
-     * Set a user readable error message. This should be set when the state is
-     * {@link PlaybackState#STATE_ERROR}.
-     */
-    public void setErrorMessage(CharSequence errorMessage) {
-        mErrorMessage = errorMessage;
-    }
-
-    /**
      * Get the {@link PlaybackState} state for the given
      * {@link RemoteControlClient} state.
      *
@@ -574,4 +490,175 @@
             return new PlaybackState[size];
         }
     };
+
+    /**
+     * Builder for {@link PlaybackState} objects.
+     */
+    public static final class Builder {
+        private int mState;
+        private long mPosition;
+        private long mBufferPosition;
+        private float mSpeed;
+        private long mActions;
+        private CharSequence mErrorMessage;
+        private long mUpdateTime;
+
+        /**
+         * Creates an initially empty state builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Creates a builder with the same initial values as those in the from
+         * state.
+         *
+         * @param from The state to use for initializing the builder.
+         */
+        public Builder(PlaybackState from) {
+            if (from == null) {
+                return;
+            }
+            mState = from.mState;
+            mPosition = from.mPosition;
+            mBufferPosition = from.mBufferPosition;
+            mSpeed = from.mSpeed;
+            mActions = from.mActions;
+            mErrorMessage = from.mErrorMessage;
+            mUpdateTime = from.mUpdateTime;
+        }
+
+        /**
+         * Set the current state of playback.
+         * <p>
+         * The position must be in ms and indicates the current playback
+         * position within the track. If the position is unknown use
+         * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
+         * position the time at which the position was updated must be provided.
+         * It is okay to use {@link SystemClock#elapsedRealtime()} if the
+         * current position was just retrieved.
+         * <p>
+         * The speed is a multiple of normal playback and should be 0 when
+         * paused and negative when rewinding. Normal playback speed is 1.0.
+         * <p>
+         * The state must be one of the following:
+         * <ul>
+         * <li> {@link PlaybackState#STATE_NONE}</li>
+         * <li> {@link PlaybackState#STATE_STOPPED}</li>
+         * <li> {@link PlaybackState#STATE_PLAYING}</li>
+         * <li> {@link PlaybackState#STATE_PAUSED}</li>
+         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
+         * <li> {@link PlaybackState#STATE_REWINDING}</li>
+         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
+         * <li> {@link PlaybackState#STATE_ERROR}</li>
+         * </ul>
+         *
+         * @param state The current state of playback.
+         * @param position The position in the current track in ms.
+         * @param playbackSpeed The current speed of playback as a multiple of
+         *            normal playback.
+         * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
+         *            timebase that the position was updated at.
+         * @return this
+         */
+        public Builder setState(int state, long position, float playbackSpeed, long updateTime) {
+            mState = state;
+            mPosition = position;
+            mUpdateTime = updateTime;
+            mSpeed = playbackSpeed;
+            return this;
+        }
+
+        /**
+         * Set the current state of playback.
+         * <p>
+         * The position must be in ms and indicates the current playback
+         * position within the track. If the position is unknown use
+         * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
+         * the current {@link SystemClock#elapsedRealtime()}.
+         * <p>
+         * The speed is a multiple of normal playback and should be 0 when
+         * paused and negative when rewinding. Normal playback speed is 1.0.
+         * <p>
+         * The state must be one of the following:
+         * <ul>
+         * <li> {@link PlaybackState#STATE_NONE}</li>
+         * <li> {@link PlaybackState#STATE_STOPPED}</li>
+         * <li> {@link PlaybackState#STATE_PLAYING}</li>
+         * <li> {@link PlaybackState#STATE_PAUSED}</li>
+         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
+         * <li> {@link PlaybackState#STATE_REWINDING}</li>
+         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
+         * <li> {@link PlaybackState#STATE_ERROR}</li>
+         * </ul>
+         *
+         * @param state The current state of playback.
+         * @param position The position in the current track in ms.
+         * @param playbackSpeed The current speed of playback as a multiple of
+         *            normal playback.
+         * @return this
+         */
+        public Builder setState(int state, long position, float playbackSpeed) {
+            return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
+        }
+
+        /**
+         * Set the current actions available on this session. This should use a
+         * bitmask of possible actions.
+         * <ul>
+         * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
+         * <li> {@link PlaybackState#ACTION_REWIND}</li>
+         * <li> {@link PlaybackState#ACTION_PLAY}</li>
+         * <li> {@link PlaybackState#ACTION_PAUSE}</li>
+         * <li> {@link PlaybackState#ACTION_STOP}</li>
+         * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
+         * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
+         * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
+         * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
+         * </ul>
+         *
+         * @param actions The set of actions allowed.
+         * @return this
+         */
+        public Builder setActions(long actions) {
+            mActions = actions;
+            return this;
+        }
+
+        /**
+         * Set the current buffer position in ms. This is the farthest playback
+         * point that can be reached from the current position using only
+         * buffered content.
+         *
+         * @param bufferPosition The position in ms that playback is buffered
+         *            to.
+         * @return this
+         */
+        public Builder setBufferPosition(long bufferPosition) {
+            mBufferPosition = bufferPosition;
+            return this;
+        }
+
+        /**
+         * Set a user readable error message. This should be set when the state
+         * is {@link PlaybackState#STATE_ERROR}.
+         *
+         * @param error The error message for display to the user.
+         * @return this
+         */
+        public Builder setErrorMessage(CharSequence error) {
+            mErrorMessage = error;
+            return this;
+        }
+
+        /**
+         * Build and return the PlaybackState instance with these values.
+         *
+         * @return A new state instance.
+         */
+        public PlaybackState build() {
+            return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferPosition,
+                    mActions, mErrorMessage);
+        }
+    }
 }
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 1685a44..5646740 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -157,6 +157,10 @@
         return;
     }
     sp<Camera> c = get_native_camera(env, camera, NULL);
+    if (c == NULL) {
+        // get_native_camera will throw an exception in this case
+        return;
+    }
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
     process_media_recorder_call(env, mr->setCamera(c->remote(), c->getRecordingProxy()),
             "java/lang/RuntimeException", "setCamera failed.");
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 223013f..260ee39 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -74,7 +74,7 @@
         </activity>
 
         <receiver
-            android:name=".NotificationController$NotificationBroadcastReceiver"
+            android:name=".model.NotificationController$NotificationBroadcastReceiver"
             android:exported="false" >
         </receiver>
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index d37ccc0..3134e93 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -56,8 +56,6 @@
     private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
 
     private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
-    private static final String EXTRA_PRINTJOB_LABEL = "EXTRA_PRINTJOB_LABEL";
-    private static final String EXTRA_PRINTER_NAME = "EXTRA_PRINTER_NAME";
 
     private final Context mContext;
     private final NotificationManager mNotificationManager;
@@ -69,7 +67,7 @@
     }
 
     public void onUpdateNotifications(List<PrintJobInfo> printJobs) {
-        List<PrintJobInfo> notifyPrintJobs = new ArrayList<PrintJobInfo>();
+        List<PrintJobInfo> notifyPrintJobs = new ArrayList<>();
 
         final int printJobCount = printJobs.size();
         for (int i = 0; i < printJobCount; i++) {
@@ -252,8 +250,6 @@
         Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
         intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + printJob.getId().flattenToString());
         intent.putExtra(EXTRA_PRINT_JOB_ID, printJob.getId());
-        intent.putExtra(EXTRA_PRINTJOB_LABEL, printJob.getLabel());
-        intent.putExtra(EXTRA_PRINTER_NAME, printJob.getPrinterName());
         return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
     }
 
@@ -302,17 +298,14 @@
             String action = intent.getAction();
             if (action != null && action.startsWith(INTENT_ACTION_CANCEL_PRINTJOB)) {
                 PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
-                String printJobLabel = intent.getExtras().getString(EXTRA_PRINTJOB_LABEL);
-                String printerName = intent.getExtras().getString(EXTRA_PRINTER_NAME);
-                handleCancelPrintJob(context, printJobId, printJobLabel, printerName);
+                handleCancelPrintJob(context, printJobId);
             } else if (action != null && action.startsWith(INTENT_ACTION_RESTART_PRINTJOB)) {
                 PrintJobId printJobId = intent.getExtras().getParcelable(EXTRA_PRINT_JOB_ID);
                 handleRestartPrintJob(context, printJobId);
             }
         }
 
-        private void handleCancelPrintJob(final Context context, final PrintJobId printJobId,
-                final String printJobLabel, final String printerName) {
+        private void handleCancelPrintJob(final Context context, final PrintJobId printJobId) {
             if (DEBUG) {
                 Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId);
             }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index e4716da..8a65a2e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -27,6 +27,7 @@
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -68,10 +69,10 @@
     private static final int MAX_FAVORITE_PRINTER_COUNT = 4;
 
     private final List<PrinterInfo> mPrinters =
-            new ArrayList<PrinterInfo>();
+            new ArrayList<>();
 
     private final List<PrinterInfo> mFavoritePrinters =
-            new ArrayList<PrinterInfo>();
+            new ArrayList<>();
 
     private final PersistenceManager mPersistenceManager;
 
@@ -92,7 +93,7 @@
 
     private void computeAndDeliverResult(ArrayMap<PrinterId, PrinterInfo> discoveredPrinters,
             ArrayMap<PrinterId, PrinterInfo> favoritePrinters) {
-        List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+        List<PrinterInfo> printers = new ArrayList<>();
 
         // Add the updated favorite printers.
         final int favoritePrinterCount = favoritePrinters.size();
@@ -142,7 +143,7 @@
         // The contract is that if we already have a valid,
         // result the we have to deliver it immediately.
         if (!mPrinters.isEmpty()) {
-            deliverResult(new ArrayList<PrinterInfo>(mPrinters));
+            deliverResult(new ArrayList<>(mPrinters));
         }
         // Always load the data to ensure discovery period is
         // started and to make sure obsolete printers are updated.
@@ -184,11 +185,12 @@
                                 + mDiscoverySession.getPrinters().size()
                                 + " " + FusedPrintersProvider.this.hashCode());
                     }
+
                     updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
                 }
             });
             final int favoriteCount = mFavoritePrinters.size();
-            List<PrinterId> printerIds = new ArrayList<PrinterId>(favoriteCount);
+            List<PrinterId> printerIds = new ArrayList<>(favoriteCount);
             for (int i = 0; i < favoriteCount; i++) {
                 printerIds.add(mFavoritePrinters.get(i).getId());
             }
@@ -208,16 +210,19 @@
 
         mPrintersUpdatedBefore = true;
 
-        ArrayMap<PrinterId, PrinterInfo> printersMap =
-                new ArrayMap<PrinterId, PrinterInfo>();
+        // Some of the found printers may have be a printer that is in the
+        // history but with its name changed. Hence, we try to update the
+        // printer to use its current name instead of the historical one.
+        mPersistenceManager.updatePrintersHistoricalNamesIfNeeded(printers);
+
+        ArrayMap<PrinterId, PrinterInfo> printersMap = new ArrayMap<>();
         final int printerCount = printers.size();
         for (int i = 0; i < printerCount; i++) {
             PrinterInfo printer = printers.get(i);
             printersMap.put(printer.getId(), printer);
         }
 
-        ArrayMap<PrinterId, PrinterInfo> favoritePrintersMap =
-                new ArrayMap<PrinterId, PrinterInfo>();
+        ArrayMap<PrinterId, PrinterInfo> favoritePrintersMap = new ArrayMap<>();
         final int favoritePrinterCount = favoritePrinters.size();
         for (int i = 0; i < favoritePrinterCount; i++) {
             PrinterInfo favoritePrinter = favoritePrinters.get(i);
@@ -310,7 +315,7 @@
         for (int i = 0; i < favoritePrinterCount; i++) {
             PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
             if (favoritePrinter.getId().equals(printerId)) {
-                newFavoritePrinters = new ArrayList<PrinterInfo>();
+                newFavoritePrinters = new ArrayList<>();
                 newFavoritePrinters.addAll(mPrinters);
                 newFavoritePrinters.remove(i);
                 break;
@@ -344,7 +349,7 @@
 
         private final AtomicFile mStatePersistFile;
 
-        private List<PrinterInfo> mHistoricalPrinters = new ArrayList<PrinterInfo>();
+        private List<PrinterInfo> mHistoricalPrinters = new ArrayList<>();
 
         private boolean mReadHistoryCompleted;
         private boolean mReadHistoryInProgress;
@@ -382,17 +387,42 @@
             mReadTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
         }
 
-        @SuppressWarnings("unchecked")
+        public void updatePrintersHistoricalNamesIfNeeded(List<PrinterInfo> printers) {
+            boolean writeHistory = false;
+
+            final int printerCount = printers.size();
+            for (int i = 0; i < printerCount; i++) {
+                PrinterInfo printer = printers.get(i);
+                writeHistory |= renamePrinterIfNeeded(printer);
+            }
+
+            if (writeHistory) {
+                writePrinterHistory();
+            }
+        }
+
+        public boolean renamePrinterIfNeeded(PrinterInfo printer) {
+            boolean renamed = false;
+            final int printerCount = mHistoricalPrinters.size();
+            for (int i = 0; i < printerCount; i++) {
+                PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
+                if (historicalPrinter.getId().equals(printer.getId())
+                        && !TextUtils.equals(historicalPrinter.getName(), printer.getName())) {
+                    mHistoricalPrinters.set(i, printer);
+                    renamed = true;
+                }
+            }
+            return renamed;
+        }
+
         public void addPrinterAndWritePrinterHistory(PrinterInfo printer) {
             if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) {
                 mHistoricalPrinters.remove(0);
             }
             mHistoricalPrinters.add(printer);
-            new WriteTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,
-                    new ArrayList<PrinterInfo>(mHistoricalPrinters));
+            writePrinterHistory();
         }
 
-        @SuppressWarnings("unchecked")
         public void removeHistoricalPrinterAndWritePrinterHistory(PrinterId printerId) {
             boolean writeHistory = false;
             final int printerCount = mHistoricalPrinters.size();
@@ -404,18 +434,22 @@
                 }
             }
             if (writeHistory) {
-                new WriteTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,
-                        new ArrayList<PrinterInfo>(mHistoricalPrinters));
+                writePrinterHistory();
             }
         }
 
+        @SuppressWarnings("unchecked")
+        private void writePrinterHistory() {
+            new WriteTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,
+                    new ArrayList<>(mHistoricalPrinters));
+        }
+
         public boolean isHistoryChanged() {
             return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
         }
 
         private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) {
-            Map<PrinterId, PrinterRecord> recordMap =
-                    new ArrayMap<PrinterId, PrinterRecord>();
+            Map<PrinterId, PrinterRecord> recordMap = new ArrayMap<>();
 
             // Recompute the weights.
             float currentWeight = 1.0f;
@@ -433,14 +467,14 @@
             }
 
             // Soft the favorite printers.
-            List<PrinterRecord> favoriteRecords = new ArrayList<PrinterRecord>(
+            List<PrinterRecord> favoriteRecords = new ArrayList<>(
                     recordMap.values());
             Collections.sort(favoriteRecords);
 
             // Write the favorites to the output.
             final int favoriteCount = Math.min(favoriteRecords.size(),
                     MAX_FAVORITE_PRINTER_COUNT);
-            List<PrinterInfo> favoritePrinters = new ArrayList<PrinterInfo>(favoriteCount);
+            List<PrinterInfo> favoritePrinters = new ArrayList<>(favoriteCount);
             for (int i = 0; i < favoriteCount; i++) {
                 PrinterInfo printer = favoriteRecords.get(i).printer;
                 favoritePrinters.add(printer);
@@ -482,7 +516,7 @@
                 List<PrintServiceInfo> services = printManager
                         .getEnabledPrintServices();
 
-                Set<ComponentName> enabledComponents = new ArraySet<ComponentName>();
+                Set<ComponentName> enabledComponents = new ArraySet<>();
                 final int installedServiceCount = services.size();
                 for (int i = 0; i < installedServiceCount; i++) {
                     ServiceInfo serviceInfo = services.get(i).getResolveInfo().serviceInfo;
@@ -528,28 +562,23 @@
                         Log.i(LOG_TAG, "No existing printer history "
                                 + FusedPrintersProvider.this.hashCode());
                     }
-                    return new ArrayList<PrinterInfo>();
+                    return new ArrayList<>();
                 }
                 try {
-                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+                    List<PrinterInfo> printers = new ArrayList<>();
                     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);
-                } catch (NullPointerException npe) {
-                    Slog.w(LOG_TAG, "Failed parsing ", npe);
-                } catch (NumberFormatException nfe) {
-                    Slog.w(LOG_TAG, "Failed parsing ", nfe);
-                } catch (XmlPullParserException xppe) {
-                    Slog.w(LOG_TAG, "Failed parsing ", xppe);
-                } catch (IOException ioe) {
-                    Slog.w(LOG_TAG, "Failed parsing ", ioe);
-                } catch (IndexOutOfBoundsException iobe) {
-                    Slog.w(LOG_TAG, "Failed parsing ", iobe);
+                } catch (IllegalStateException
+                        | NullPointerException
+                        | NumberFormatException
+                        | XmlPullParserException
+                        | IOException
+                        | IndexOutOfBoundsException e) {
+                    Slog.w(LOG_TAG, "Failed parsing ", e);
                 } finally {
                     IoUtils.closeQuietly(in);
                 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index eaf268d..094edf8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -389,6 +389,7 @@
             mSelectedPages = selectedPages;
             mSelectedPageCount = PageRangeUtils.getNormalizedPageCount(
                     mSelectedPages, mDocumentPageCount);
+            updatePreviewAreaAndPageSize();
             notifyDataSetChanged();
         }
         return mSelectedPages;
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b79dbbe..d4feccd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -516,6 +516,10 @@
     <string name="quick_settings_time_label">Time</string>
     <!-- QuickSettings: User [CHAR LIMIT=NONE] -->
     <string name="quick_settings_user_label">Me</string>
+    <!-- QuickSettings: Title of the user detail panel [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_user_title">User</string>
+    <!-- QuickSettings: Label on the item for adding a new user [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_user_new_user">New user</string>
     <!-- QuickSettings: Wifi [CHAR LIMIT=NONE] -->
     <string name="quick_settings_wifi_label">Wi-Fi</string>
     <!-- QuickSettings: Wifi (Not connected) [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index a9a606f..b6d7d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -64,11 +64,9 @@
 
     Context mContext;
     SystemServicesProxy mSystemServicesProxy;
-
-    // Recents service binding
     Handler mHandler;
-    boolean mBootCompleted = false;
-    boolean mStartAnimationTriggered = false;
+    boolean mBootCompleted;
+    boolean mStartAnimationTriggered;
 
     // Task launching
     RecentsConfiguration mConfig;
@@ -95,9 +93,7 @@
     }
 
     public void onStart() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|start]");
-        }
+        // Do nothing
     }
 
     public void onBootCompleted() {
@@ -106,9 +102,6 @@
 
     /** Shows the recents */
     public void onShowRecents(boolean triggeredFromAltTab, View statusBarView) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|showRecents]");
-        }
         mStatusBarView = statusBarView;
         mTriggeredFromAltTab = triggeredFromAltTab;
 
@@ -121,10 +114,6 @@
 
     /** Hides the recents */
     public void onHideRecents(boolean triggeredFromAltTab) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]");
-        }
-
         if (mBootCompleted) {
             if (isRecentsTopMost(getTopMostTask(), null)) {
                 // Notify recents to hide itself
@@ -139,13 +128,6 @@
 
     /** Toggles the alternate recents activity */
     public void onToggleRecents(View statusBarView) {
-        if (Console.Enabled) {
-            Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
-                    Constants.Log.App.TimeRecentsStartupKey);
-            Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
-                    Constants.Log.App.TimeRecentsLaunchKey);
-            Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]", "");
-        }
         mStatusBarView = statusBarView;
         mTriggeredFromAltTab = false;
 
@@ -223,14 +205,6 @@
             intent.setPackage(mContext.getPackageName());
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
             mContext.sendBroadcast(intent);
-
-            // Time this path
-            if (Console.Enabled) {
-                Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                        Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
-                Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                        Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
-            }
             mLastToggleTime = System.currentTimeMillis();
             return;
         } else {
@@ -395,11 +369,6 @@
                 startAlternateRecentsActivity(topTask, opts, null);
             }
         }
-
-        if (Console.Enabled) {
-            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                    Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
-        }
         mLastToggleTime = System.currentTimeMillis();
     }
 
@@ -417,10 +386,9 @@
         intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab);
         intent.putExtra(EXTRA_TRIGGERED_FROM_TASK_ID, (topTask != null) ? topTask.id : -1);
         if (opts != null) {
-            mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
-                    UserHandle.USER_CURRENT));
+            mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
         } else {
-            mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 8a80b76..c49e244 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -32,7 +32,7 @@
             // Enables the filtering of tasks according to their grouping
             public static final boolean EnableTaskFiltering = false;
             // Enables clipping of tasks against each other
-            public static final boolean EnableTaskStackClipping = true;
+            public static final boolean EnableTaskStackClipping = false;
             // Enables tapping on the TaskBar to launch the task
             public static final boolean EnableTaskBarTouchEvents = true;
             // Enables app-info pane on long-pressing the icon
@@ -52,43 +52,6 @@
         }
     }
 
-    public static class Log {
-        public static class App {
-            public static final String TimeRecentsStartupKey = "startup";
-            public static final String TimeRecentsLaunchKey = "launchTask";
-            public static final String TimeRecentsScreenshotTransitionKey = "screenshot";
-            public static final boolean TimeRecentsStartup = false;
-            public static final boolean TimeRecentsLaunchTask = false;
-            public static final boolean TimeRecentsScreenshotTransition = false;
-
-
-            public static final boolean RecentsComponent = false;
-            public static final boolean TaskDataLoader = false;
-            public static final boolean SystemUIHandshake = false;
-            public static final boolean TimeSystemCalls = false;
-            public static final boolean Memory = false;
-            public static final boolean Search = false;
-        }
-
-        public static class UI {
-            public static final boolean Draw = false;
-            public static final boolean ClickEvents = false;
-            public static final boolean TouchEvents = false;
-            public static final boolean MeasureAndLayout = false;
-            public static final boolean HwLayers = false;
-            public static final boolean Focus = false;
-        }
-
-        public static class TaskStack {
-            public static final boolean SynchronizeViewsWithModel = false;
-        }
-
-        public static class ViewPool {
-            public static final boolean PoolCallbacks = false;
-        }
-    }
-
-    /** XXX: We are going to move almost all of these into a resource once they are nailed down. */
     public static class Values {
         public static class App {
             public static int AppWidgetHostId = 1024;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 56de0be..29a0262 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -52,16 +52,23 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 
-/* Activity */
+/**
+ * The main Recents activity that is started from AlternateRecentsComponent.
+ */
 public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
         RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
         FullscreenTransitionOverlayView.FullScreenTransitionViewCallbacks {
 
+    // Actions and Extras sent from AlternateRecentsComponent
     final static String EXTRA_TRIGGERED_FROM_ALT_TAB = "extra_triggered_from_alt_tab";
     final static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
     final static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
     final static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
 
+    RecentsConfiguration mConfig;
+    boolean mVisible;
+
+    // Top level views
     RecentsView mRecentsView;
     SystemBarScrimViews mScrimViews;
     ViewStub mEmptyViewStub;
@@ -69,29 +76,29 @@
     ViewStub mFullscreenOverlayStub;
     FullscreenTransitionOverlayView mFullScreenOverlayView;
 
-    RecentsConfiguration mConfig;
-
+    // Search AppWidget
     RecentsAppWidgetHost mAppWidgetHost;
     AppWidgetProviderInfo mSearchAppWidgetInfo;
     AppWidgetHostView mSearchAppWidgetHostView;
 
-    boolean mVisible;
 
     // Runnables to finish the Recents activity
-    FinishRecentsRunnable mFinishRunnable = new FinishRecentsRunnable(true);
+    FinishRecentsRunnable mFinishRunnable = new FinishRecentsRunnable();
     FinishRecentsRunnable mFinishLaunchHomeRunnable;
 
     /**
-     * A Runnable to finish Recents either with/without a transition, and either by calling finish()
-     * or just launching the specified intent.
+     * A common Runnable to finish Recents either by calling finish() (with a custom animation) or
+     * launching Home with some ActivityOptions.  Generally we always launch home when we exit
+     * Recents rather than just finishing the activity since we don't know what is behind Recents in
+     * the task stack.  The only case where we finish() directly is when we are cancelling the full
+     * screen transition from the app.
      */
     class FinishRecentsRunnable implements Runnable {
-        boolean mUseCustomFinishTransition;
         Intent mLaunchIntent;
         ActivityOptions mLaunchOpts;
 
-        public FinishRecentsRunnable(boolean withTransition) {
-            mUseCustomFinishTransition = withTransition;
+        public FinishRecentsRunnable() {
+            // Do nothing
         }
 
         /**
@@ -111,77 +118,66 @@
             // Finish Recents
             if (mLaunchIntent != null) {
                 if (mLaunchOpts != null) {
-                    startActivityAsUser(mLaunchIntent, new UserHandle(UserHandle.USER_CURRENT));
+                    startActivityAsUser(mLaunchIntent, UserHandle.CURRENT);
                 } else {
-                    startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(),
-                            new UserHandle(UserHandle.USER_CURRENT));
+                    startActivityAsUser(mLaunchIntent, mLaunchOpts.toBundle(), UserHandle.CURRENT);
                 }
             } else {
                 finish();
-                if (mUseCustomFinishTransition) {
-                    overridePendingTransition(R.anim.recents_to_launcher_enter,
-                            R.anim.recents_to_launcher_exit);
-                }
+                overridePendingTransition(R.anim.recents_to_launcher_enter,
+                        R.anim.recents_to_launcher_exit);
             }
         }
     }
 
-    // Broadcast receiver to handle messages from AlternateRecentsComponent
+    /**
+     * Broadcast receiver to handle messages from AlternateRecentsComponent.
+     */
     final BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (Console.Enabled) {
-                Console.log(Constants.Log.App.SystemUIHandshake,
-                        "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
-            }
             if (action.equals(ACTION_HIDE_RECENTS_ACTIVITY)) {
                 if (intent.getBooleanExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
-                    // Dismiss recents, launching the focused task
-                    dismissRecentsIfVisible();
+                    // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
+                    dismissRecentsToFocusedTaskOrHome(false);
                 } else {
-                    // If we are mid-animation into Recents, then reverse it and finish
-                    if (mFullScreenOverlayView == null ||
-                            !mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
-                        // Otherwise, either finish Recents, or launch Home directly
-                        ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(context,
-                                null, mFinishLaunchHomeRunnable, null);
-                        mRecentsView.startExitToHomeAnimation(
-                                new ViewAnimation.TaskViewExitContext(exitTrigger));
-                    }
+                    // Otherwise, dismiss Recents to Home
+                    dismissRecentsToHome(true);
                 }
             } else if (action.equals(ACTION_TOGGLE_RECENTS_ACTIVITY)) {
-                // Try and unfilter and filtered stacks
-                if (!mRecentsView.unfilterFilteredStacks()) {
-                    // If there are no filtered stacks, dismiss recents and launch the first task
-                    dismissRecentsIfVisible();
-                }
+                // If we are toggling Recents, then first unfilter any filtered stacks first
+                dismissRecentsToFocusedTaskOrHome(true);
             } else if (action.equals(ACTION_START_ENTER_ANIMATION)) {
                 // Try and start the enter animation (or restart it on configuration changed)
                 ReferenceCountedTrigger t = new ReferenceCountedTrigger(context, null, null, null);
                 mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(
                         mFullScreenOverlayView, t));
-                // Call our callback
                 onEnterAnimationTriggered();
             }
         }
     };
 
-    // Broadcast receiver to handle messages from the system
+    /**
+     * Broadcast receiver to handle messages from the system
+     */
     final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(Intent.ACTION_SCREEN_OFF) && mVisible) {
-                mFinishLaunchHomeRunnable.run();
+            if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+                // When the screen turns off, dismiss Recents to Home
+                dismissRecentsToHome(false);
             } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
-                // Refresh the search widget
+                // When the search activity changes, update the Search widget
                 refreshSearchWidget();
             }
         }
     };
 
-    // Debug trigger
+    /**
+     * A custom debug trigger to listen for a debug key chord.
+     */
     final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
         @Override
         public void run() {
@@ -211,15 +207,17 @@
         mConfig.launchedToTaskId = launchIntent.getIntExtra(
                 AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_TASK_ID, -1);
 
-        // Add the default no-recents layout
-        if (mEmptyView == null) {
-            mEmptyView = mEmptyViewStub.inflate();
-        }
+        // Update the top level view's visibilities
         if (mConfig.launchedWithNoRecentTasks) {
+            if (mEmptyView == null) {
+                mEmptyView = mEmptyViewStub.inflate();
+            }
             mEmptyView.setVisibility(View.VISIBLE);
             mRecentsView.setSearchBarVisibility(View.GONE);
         } else {
-            mEmptyView.setVisibility(View.GONE);
+            if (mEmptyView != null) {
+                mEmptyView.setVisibility(View.GONE);
+            }
             if (mRecentsView.hasSearchBar()) {
                 mRecentsView.setSearchBarVisibility(View.VISIBLE);
             } else {
@@ -227,7 +225,7 @@
             }
         }
 
-        // Show the scrim if we animate into Recents without window transitions
+        // Animate the SystemUI scrims into view
         mScrimViews.prepareEnterRecentsAnimation();
     }
 
@@ -250,12 +248,6 @@
                     ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
                     appWidgetId = -1;
                 }
-                if (Console.Enabled) {
-                    Console.log(Constants.Log.App.SystemUIHandshake,
-                            "[RecentsActivity|onCreate|settings|appWidgetId]",
-                            "Id: " + appWidgetId,
-                            Console.AnsiBlue);
-                }
             }
 
             // If there is no id, then bind a new search app widget
@@ -263,13 +255,6 @@
                 Pair<Integer, AppWidgetProviderInfo> widgetInfo =
                         ssp.bindSearchAppWidget(mAppWidgetHost);
                 if (widgetInfo != null) {
-                    if (Console.Enabled) {
-                        Console.log(Constants.Log.App.SystemUIHandshake,
-                                "[RecentsActivity|onCreate|searchWidget]",
-                                "Id: " + widgetInfo.first + " Info: " + widgetInfo.second,
-                                Console.AnsiBlue);
-                    }
-
                     // Save the app widget id into the settings
                     mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first);
                     mSearchAppWidgetInfo = widgetInfo.second;
@@ -283,12 +268,6 @@
         if (Constants.DebugFlags.App.EnableSearchLayout) {
             int appWidgetId = mConfig.searchBarAppWidgetId;
             if (appWidgetId >= 0) {
-                if (Console.Enabled) {
-                    Console.log(Constants.Log.App.SystemUIHandshake,
-                            "[RecentsActivity|onCreate|addSearchAppWidgetView]",
-                            "Id: " + appWidgetId,
-                            Console.AnsiBlue);
-                }
                 mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
                         mSearchAppWidgetInfo);
                 Bundle opts = new Bundle();
@@ -305,28 +284,50 @@
     }
 
     /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
-    boolean dismissRecentsIfVisible() {
+    boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
         if (mVisible) {
-            // If we are mid-animation into Recents, then reverse it and finish
-            if (mFullScreenOverlayView == null ||
-                    !mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
-                // If we have a focused task, then launch that task
-                if (!mRecentsView.launchFocusedTask()) {
-                    if (mConfig.launchedFromHome) {
-                        // Just start the animation out of recents
-                        ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
-                                null, mFinishLaunchHomeRunnable, null);
-                        mRecentsView.startExitToHomeAnimation(
-                                new ViewAnimation.TaskViewExitContext(exitTrigger));
-                    } else {
-                        // Otherwise, try and launch the first task
-                        if (!mRecentsView.launchFirstTask()) {
-                            // If there are no tasks, then just finish recents
-                            mFinishLaunchHomeRunnable.run();
-                        }
-                    }
-                }
+            // If we are mid-animation into Recents, reverse the animation now
+            if (mFullScreenOverlayView != null &&
+                mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) return true;
+            // If we currently have filtered stacks, then unfilter those first
+            if (checkFilteredStackState &&
+                mRecentsView.unfilterFilteredStacks()) return true;
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchFocusedTask()) return true;
+            // If we launched from Home, then return to Home
+            if (mConfig.launchedFromHome) {
+                dismissRecentsToHomeRaw(true);
+                return true;
             }
+            // Otherwise, try and return to the first Task in the stack
+            if (mRecentsView.launchFirstTask()) return true;
+            // If none of the other cases apply, then just go Home
+            dismissRecentsToHomeRaw(true);
+            return true;
+        }
+        return false;
+    }
+
+    /** Dismisses Recents directly to Home. */
+    void dismissRecentsToHomeRaw(boolean animated) {
+        if (animated) {
+            ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+                    null, mFinishLaunchHomeRunnable, null);
+            mRecentsView.startExitToHomeAnimation(
+                    new ViewAnimation.TaskViewExitContext(exitTrigger));
+        } else {
+            mFinishLaunchHomeRunnable.run();
+        }
+    }
+
+    /** Dismisses Recents directly to Home if we currently aren't transitioning. */
+    boolean dismissRecentsToHome(boolean animated) {
+        if (mVisible) {
+            // If we are mid-animation into Recents, reverse the animation now
+            if (mFullScreenOverlayView != null &&
+                mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) return true;
+            // Return to Home
+            dismissRecentsToHomeRaw(animated);
             return true;
         }
         return false;
@@ -336,13 +337,6 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        if (Console.Enabled) {
-            Console.logDivider(Constants.Log.App.SystemUIHandshake);
-            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
-                    getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed);
-            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                    Constants.Log.App.TimeRecentsStartupKey, "onCreate");
-        }
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
@@ -410,11 +404,13 @@
     }
 
     void onConfigurationChange() {
+        // Update RecentsConfiguration
+        mConfig = RecentsConfiguration.reinitialize(this);
+
         // Try and start the enter animation (or restart it on configuration changed)
         ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
         mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(
                 mFullScreenOverlayView, t));
-        // Call our callback
         onEnterAnimationTriggered();
     }
 
@@ -423,18 +419,6 @@
         super.onNewIntent(intent);
         setIntent(intent);
 
-        if (Console.Enabled) {
-            Console.logDivider(Constants.Log.App.SystemUIHandshake);
-            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
-                    intent.getAction() + " visible: " + mVisible, Console.AnsiRed);
-            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                    Constants.Log.App.TimeRecentsStartupKey, "onNewIntent");
-        }
-
-        // Initialize the loader and the configuration
-        RecentsTaskLoader.initialize(this);
-        mConfig = RecentsConfiguration.reinitialize(this);
-
         // Update the recent tasks
         updateRecentsTasks(intent);
 
@@ -446,10 +430,6 @@
 
     @Override
     protected void onStart() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
-                    Console.AnsiRed);
-        }
         super.onStart();
 
         // Register the broadcast receiver to handle messages from our service
@@ -458,16 +438,10 @@
         filter.addAction(ACTION_TOGGLE_RECENTS_ACTIVITY);
         filter.addAction(ACTION_START_ENTER_ANIMATION);
         registerReceiver(mServiceBroadcastReceiver, filter);
-
-        mVisible = true;
     }
 
     @Override
     protected void onResume() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
-                    Console.AnsiRed);
-        }
         super.onResume();
 
         // Start listening for widget package changes if there is one bound, post it since we don't
@@ -485,63 +459,29 @@
                 }
             }, 1);
         }
-    }
 
-    @Override
-    public void onAttachedToWindow() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.SystemUIHandshake,
-                    "[RecentsActivity|onAttachedToWindow]", "",
-                    Console.AnsiRed);
-        }
-        super.onAttachedToWindow();
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.SystemUIHandshake,
-                    "[RecentsActivity|onDetachedFromWindow]", "",
-                    Console.AnsiRed);
-        }
-        super.onDetachedFromWindow();
-    }
-
-    @Override
-    protected void onPause() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
-                    Console.AnsiRed);
-        }
-        super.onPause();
+        // Mark Recents as visible
+        mVisible = true;
     }
 
     @Override
     protected void onStop() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
-                    Console.AnsiRed);
-        }
         super.onStop();
 
         // Unregister the RecentsService receiver
         unregisterReceiver(mServiceBroadcastReceiver);
 
         // Stop listening for widget package changes if there was one bound
-        if (mConfig.searchBarAppWidgetId >= 0) {
+        if (mAppWidgetHost.isListening()) {
             mAppWidgetHost.stopListening();
         }
     }
 
     @Override
     protected void onDestroy() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
-                    Console.AnsiRed);
-        }
         super.onDestroy();
 
-        // Unregister the screen off receiver
+        // Unregister the system broadcast receivers
         unregisterReceiver(mSystemBroadcastReceiver);
         RecentsTaskLoader.getInstance().unregisterReceivers();
     }
@@ -583,26 +523,8 @@
         // Test mode where back does not do anything
         if (mConfig.debugModeEnabled) return;
 
-        // If we are mid-animation into Recents, then reverse it and finish
-        if (mFullScreenOverlayView == null ||
-                !mFullScreenOverlayView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
-            // If we are currently filtering in any stacks, unfilter them first
-            if (!mRecentsView.unfilterFilteredStacks()) {
-                if (mConfig.launchedFromHome) {
-                    // Just start the animation out of recents
-                    ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
-                            null, mFinishLaunchHomeRunnable, null);
-                    mRecentsView.startExitToHomeAnimation(
-                            new ViewAnimation.TaskViewExitContext(exitTrigger));
-                } else {
-                    // Otherwise, try and launch the first task
-                    if (!mRecentsView.launchFirstTask()) {
-                        // If there are no tasks, then just finish recents
-                        mFinishLaunchHomeRunnable.run();
-                    }
-                }
-            }
-        }
+        // Dismiss Recents to the focused Task or Home
+        dismissRecentsToFocusedTaskOrHome(true);
     }
 
     /** Called when debug mode is triggered */
@@ -623,7 +545,7 @@
 
     /** Called when the enter recents animation is triggered. */
     public void onEnterAnimationTriggered() {
-        // Animate the scrims in
+        // Animate the SystemUI scrim views
         mScrimViews.startEnterRecentsAnimation();
     }
 
@@ -644,7 +566,7 @@
 
     @Override
     public void onExitToHomeAnimationTriggered() {
-        // Animate the scrims out
+        // Animate the SystemUI scrim views out
         mScrimViews.startExitRecentsAnimation();
     }
 
@@ -664,7 +586,6 @@
 
     @Override
     public void refreshSearchWidget() {
-        // Load the Search widget again
         bindSearchBarAppWidget();
         addSearchBarAppWidgetView();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index 43d7a54..a63e167 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -33,6 +33,7 @@
     Context mContext;
     RecentsAppWidgetHostCallbacks mCb;
     RecentsConfiguration mConfig;
+    boolean mIsListening;
 
     public RecentsAppWidgetHost(Context context, int hostId) {
         super(context, hostId);
@@ -42,6 +43,7 @@
 
     public void startListening(RecentsAppWidgetHostCallbacks cb) {
         mCb = cb;
+        mIsListening = true;
         super.startListening();
     }
 
@@ -51,6 +53,11 @@
         // Ensure that we release any references to the callbacks
         mCb = null;
         mContext = null;
+        mIsListening = false;
+    }
+
+    public boolean isListening() {
+        return mIsListening;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index e62d989..439765e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -35,6 +35,7 @@
  * NOTE: We should not hold any references to a Context from a static instance */
 public class RecentsConfiguration {
     static RecentsConfiguration sInstance;
+    static int sPrevConfigurationHashCode;
 
     DisplayMetrics mDisplayMetrics;
 
@@ -138,7 +139,11 @@
         if (sInstance == null) {
             sInstance = new RecentsConfiguration(context);
         }
-        sInstance.update(context);
+        int configHashCode = context.getResources().getConfiguration().hashCode();
+        if (sPrevConfigurationHashCode != configHashCode) {
+            sInstance.update(context);
+            sPrevConfigurationHashCode = configHashCode;
+        }
         return sInstance;
     }
 
@@ -179,10 +184,8 @@
         transposeRecentsLayoutWithOrientation =
                 res.getBoolean(R.bool.recents_transpose_layout_with_orientation);
 
-        // Search bar
+        // Search Bar
         searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-
-        // Update the search widget id
         searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
 
         // Task stack
@@ -242,12 +245,6 @@
         // Nav bar scrim
         navBarScrimEnterDuration =
                 res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
-
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.MeasureAndLayout,
-                    "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
-                    Console.AnsiGreen);
-        }
     }
 
     /** Updates the system insets */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
index 31825af..4c0ff48 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
@@ -72,7 +72,12 @@
 
     /** Adds a runnable to the last-decrement runnables list. */
     public void addLastDecrementRunnable(Runnable r) {
+        // To ensure that the last decrement always calls, we increment and decrement after setting
+        // the last decrement runnable
+        boolean ensureLastDecrement = (mCount == 0);
+        if (ensureLastDecrement) increment();
         mLastDecRunnables.add(r);
+        if (ensureLastDecrement) decrement();
     }
 
     /** Decrements the ref count */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index b8beda6f..ced4043 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -31,6 +31,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -80,6 +81,8 @@
     ComponentName mAssistComponent;
 
     Bitmap mDummyIcon;
+    int mDummyThumbnailWidth;
+    int mDummyThumbnailHeight;
     Paint mBgProtectionPaint;
     Canvas mBgProtectionCanvas;
 
@@ -96,6 +99,13 @@
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
 
+        // Get the dummy thumbnail width/heights
+        Resources res = context.getResources();
+        int wId = com.android.internal.R.dimen.thumbnail_width;
+        int hId = com.android.internal.R.dimen.thumbnail_height;
+        mDummyThumbnailWidth = res.getDimensionPixelSize(wId);
+        mDummyThumbnailHeight = res.getDimensionPixelSize(hId);
+
         // Create the protection paints
         mBgProtectionPaint = new Paint();
         mBgProtectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
@@ -213,7 +223,8 @@
 
         // If we are mocking, then just return a dummy thumbnail
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
-            Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+            Bitmap thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, mDummyThumbnailHeight,
+                    Bitmap.Config.ARGB_8888);
             thumbnail.eraseColor(0xff333333);
             return thumbnail;
         }
@@ -239,6 +250,8 @@
      */
     public static Bitmap getThumbnail(ActivityManager activityManager, int taskId) {
         ActivityManager.TaskThumbnail taskThumbnail = activityManager.getTaskThumbnail(taskId);
+        if (taskThumbnail == null) return null;
+
         Bitmap thumbnail = taskThumbnail.mainThumbnail;
         ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
         if (thumbnail == null && descriptor != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index bda195b..607e155 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -16,16 +16,10 @@
 
 package com.android.systemui.recents.misc;
 
-import android.app.ActivityManager;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.ParcelFileDescriptor;
 import com.android.systemui.recents.RecentsConfiguration;
 
-import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
@@ -73,22 +67,25 @@
         }
     }
 
-    /** Calculates the luminance-preserved greyscale of a given color. */
-    public static int colorToGreyscale(int color) {
-        return Math.round(0.2126f * Color.red(color) + 0.7152f * Color.green(color) +
-                0.0722f * Color.blue(color));
-    }
+    /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
+    public static float computeContrastBetweenColors(int bg, int fg) {
+        float bgR = Color.red(bg) / 255f;
+        float bgG = Color.green(bg) / 255f;
+        float bgB = Color.blue(bg) / 255f;
+        bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);
+        bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
+        bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
+        float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
+        
+        float fgR = Color.red(fg) / 255f;
+        float fgG = Color.green(fg) / 255f;
+        float fgB = Color.blue(fg) / 255f;
+        fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);
+        fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);
+        fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);
+        float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;
 
-    /** Returns the ideal color to draw on top of a specified background color. */
-    public static int getIdealColorForBackgroundColorGreyscale(int greyscale, int lightRes,
-                                                               int darkRes) {
-        return (greyscale < 128) ? lightRes : darkRes;
-    }
-    /** Returns the ideal drawable to draw on top of a specified background color. */
-    public static Drawable getIdealResourceForBackgroundColorGreyscale(int greyscale,
-                                                                       Drawable lightRes,
-                                                                       Drawable darkRes) {
-        return (greyscale < 128) ? lightRes : darkRes;
+        return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
     }
 
     /** Sets some private shadow properties. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/BitmapLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/BitmapLruCache.java
index 1344729..757c07f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/BitmapLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/BitmapLruCache.java
@@ -29,6 +29,6 @@
     @Override
     protected int computeSize(Bitmap b) {
         // The cache size will be measured in kilobytes rather than number of items
-        return b.getAllocationByteCount() / 1024;
+        return b.getAllocationByteCount();
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/DrawableLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/DrawableLruCache.java
index 61d19da..5b50358 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/DrawableLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/DrawableLruCache.java
@@ -31,6 +31,6 @@
         // The cache size will be measured in kilobytes rather than number of items
         // NOTE: this isn't actually correct, as the icon may be smaller
         int maxBytes = (d.getIntrinsicWidth() * d.getIntrinsicHeight() * 4);
-        return maxBytes / 1024;
+        return maxBytes;
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
index 3ccca9a..5f4fabe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
@@ -73,11 +73,6 @@
         return mCache.get(key);
     }
 
-    /** Gets the previous task key that matches the specified key. */
-    final Task.TaskKey getKey(Task.TaskKey key) {
-        return mKeys.get(key);
-    }
-
     /** Puts an entry in the cache for a specific key. */
     final void put(Task.TaskKey key, V value) {
         mCache.put(key, value);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index 2d50659..2f1c1c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -45,7 +45,7 @@
         mSystemServicesProxy = new SystemServicesProxy(context);
         mCb = cb;
         try {
-            register(context, Looper.getMainLooper(), false);
+            register(context, Looper.getMainLooper(), true);
         } catch (IllegalStateException e) {
             e.printStackTrace();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 854ea1c..71979c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -27,38 +27,25 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.UserHandle;
-import android.util.Pair;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
-import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 
 /** A bitmap load queue */
 class TaskResourceLoadQueue {
     ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
-    ConcurrentHashMap<Task.TaskKey, Boolean> mForceLoadSet =
-            new ConcurrentHashMap<Task.TaskKey, Boolean>();
-
-    static final Boolean sFalse = new Boolean(false);
 
     /** Adds a new task to the load queue */
-    void addTask(Task t, boolean forceLoad) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
-        }
+    void addTask(Task t) {
         if (!mQueue.contains(t)) {
             mQueue.add(t);
         }
-        if (forceLoad) {
-            mForceLoadSet.put(t.key, new Boolean(true));
-        }
         synchronized(this) {
             notifyAll();
         }
@@ -68,37 +55,18 @@
      * Retrieves the next task from the load queue, as well as whether we want that task to be
      * force reloaded.
      */
-    Pair<Task, Boolean> nextTask() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
-        }
-        Task task = mQueue.poll();
-        Boolean forceLoadTask = null;
-        if (task != null) {
-            forceLoadTask = mForceLoadSet.remove(task.key);
-        }
-        if (forceLoadTask == null) {
-            forceLoadTask = sFalse;
-        }
-        return new Pair<Task, Boolean>(task, forceLoadTask);
+    Task nextTask() {
+        return mQueue.poll();
     }
 
     /** Removes a task from the load queue */
     void removeTask(Task t) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
-        }
         mQueue.remove(t);
-        mForceLoadSet.remove(t.key);
     }
 
     /** Clears all the tasks from the load queue */
     void clearTasks() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
-        }
         mQueue.clear();
-        mForceLoadSet.clear();
     }
 
     /** Returns whether the load queue is empty */
@@ -119,19 +87,20 @@
     DrawableLruCache mApplicationIconCache;
     BitmapLruCache mThumbnailCache;
     Bitmap mDefaultThumbnail;
+    BitmapDrawable mDefaultApplicationIcon;
 
     boolean mCancelled;
     boolean mWaitingOnLoadQueue;
 
     /** Constructor, creates a new loading thread that loads task resources in the background */
-    public TaskResourceLoader(TaskResourceLoadQueue loadQueue,
-                              DrawableLruCache applicationIconCache,
-                              BitmapLruCache thumbnailCache,
-                              Bitmap defaultThumbnail) {
+    public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache applicationIconCache,
+                              BitmapLruCache thumbnailCache, Bitmap defaultThumbnail,
+                              BitmapDrawable defaultApplicationIcon) {
         mLoadQueue = loadQueue;
         mApplicationIconCache = applicationIconCache;
         mThumbnailCache = thumbnailCache;
         mDefaultThumbnail = defaultThumbnail;
+        mDefaultApplicationIcon = defaultApplicationIcon;
         mMainThreadHandler = new Handler();
         mLoadThread = new HandlerThread("Recents-TaskResourceLoader");
         mLoadThread.setPriority(Thread.NORM_PRIORITY - 1);
@@ -142,9 +111,6 @@
 
     /** Restarts the loader thread */
     void start(Context context) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|start]");
-        }
         mContext = context;
         mCancelled = false;
         mSystemServicesProxy = new SystemServicesProxy(context);
@@ -156,9 +122,6 @@
 
     /** Requests the loader thread to stop after the current iteration */
     void stop() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|stop]");
-        }
         // Mark as cancelled for the thread to pick up
         mCancelled = true;
         mSystemServicesProxy = null;
@@ -172,25 +135,13 @@
     @Override
     public void run() {
         while (true) {
-            if (Console.Enabled) {
-                Console.log(Constants.Log.App.TaskDataLoader,
-                        "[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]");
-            }
             if (mCancelled) {
-                if (Console.Enabled) {
-                    Console.log(Constants.Log.App.TaskDataLoader,
-                            "[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]");
-                }
                 // We have to unset the context here, since the background thread may be using it
                 // when we call stop()
                 mContext = null;
                 // If we are cancelled, then wait until we are started again
                 synchronized(mLoadThread) {
                     try {
-                        if (Console.Enabled) {
-                            Console.log(Constants.Log.App.TaskDataLoader,
-                                    "[TaskResourceLoader|waitOnLoadThreadCancelled]");
-                        }
                         mLoadThread.wait();
                     } catch (InterruptedException ie) {
                         ie.printStackTrace();
@@ -200,59 +151,38 @@
                 SystemServicesProxy ssp = mSystemServicesProxy;
 
                 // Load the next item from the queue
-                Pair<Task, Boolean> nextTaskData = mLoadQueue.nextTask();
-                final Task t = nextTaskData.first;
-                final boolean forceLoadTask = nextTaskData.second;
+                final Task t = mLoadQueue.nextTask();
                 if (t != null) {
-                    Drawable loadIcon = mApplicationIconCache.getCheckLastActiveTime(t.key);
-                    Bitmap loadThumbnail = mThumbnailCache.getCheckLastActiveTime(t.key);
-                    if (Console.Enabled) {
-                        Console.log(Constants.Log.App.TaskDataLoader,
-                                "  [TaskResourceLoader|load]",
-                                t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
-                                        " forceLoad: " + forceLoadTask);
-                    }
-                    // Load the application icon
-                    if (loadIcon == null || forceLoadTask) {
+                    Drawable cachedIcon = mApplicationIconCache.getCheckLastActiveTime(t.key);
+                    Bitmap cachedThumbnail = mThumbnailCache.getCheckLastActiveTime(t.key);
+                    // Load the application icon if it is stale or we haven't cached one yet
+                    if (cachedIcon == null) {
+                        Drawable icon = null;
                         ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
                                 t.userId);
-                        Drawable icon = ssp.getActivityIcon(info, t.userId);
-                        if (!mCancelled) {
-                            if (icon != null) {
-                                if (Console.Enabled) {
-                                    Console.log(Constants.Log.App.TaskDataLoader,
-                                            "    [TaskResourceLoader|loadIcon]", icon);
-                                }
-                                loadIcon = icon;
-                                mApplicationIconCache.put(t.key, icon);
-                            }
+                        if (info != null) {
+                            icon = ssp.getActivityIcon(info, t.userId);
                         }
+                        // If we can't load the icon, then set the default application icon into the
+                        // cache.  This will remain until the task's last active time is updated.
+                        cachedIcon = icon != null ? icon : mDefaultApplicationIcon;
+                        mApplicationIconCache.put(t.key, cachedIcon);
                     }
-                    // Load the thumbnail
-                    if (loadThumbnail == null || forceLoadTask) {
+                    // Load the thumbnail if it is stale or we haven't cached one yet
+                    if (cachedThumbnail == null) {
                         Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
-                        if (!mCancelled) {
-                            if (thumbnail != null) {
-                                if (Console.Enabled) {
-                                    Console.log(Constants.Log.App.TaskDataLoader,
-                                            "    [TaskResourceLoader|loadThumbnail]", thumbnail);
-                                }
-                                thumbnail.setHasAlpha(false);
-                                loadThumbnail = thumbnail;
-                            } else {
-                                loadThumbnail = mDefaultThumbnail;
-                                Console.logError(mContext,
-                                        "Failed to load task top thumbnail for: " +
-                                                t.key.baseIntent.getComponent().getPackageName());
-                            }
-                            // We put the default thumbnail in the cache anyways
-                            mThumbnailCache.put(t.key, loadThumbnail);
+                        if (thumbnail != null) {
+                            thumbnail.setHasAlpha(false);
                         }
+                        // Even if we can't load the icon, we set the default thumbnail into the
+                        // cache.  This will remain until the task's last active time is updated.
+                        cachedThumbnail = thumbnail != null ? thumbnail : mDefaultThumbnail;
+                        mThumbnailCache.put(t.key, cachedThumbnail);
                     }
                     if (!mCancelled) {
                         // Notify that the task data has changed
-                        final Drawable newIcon = loadIcon;
-                        final Bitmap newThumbnail = loadThumbnail;
+                        final Drawable newIcon = cachedIcon;
+                        final Bitmap newThumbnail = cachedThumbnail;
                         mMainThreadHandler.post(new Runnable() {
                             @Override
                             public void run() {
@@ -266,10 +196,6 @@
                 if (!mCancelled && mLoadQueue.isEmpty()) {
                     synchronized(mLoadQueue) {
                         try {
-                            if (Console.Enabled) {
-                                Console.log(Constants.Log.App.TaskDataLoader,
-                                        "[TaskResourceLoader|waitOnLoadQueue]");
-                            }
                             mWaitingOnLoadQueue = true;
                             mLoadQueue.wait();
                             mWaitingOnLoadQueue = false;
@@ -306,22 +232,16 @@
     /** Private Constructor */
     private RecentsTaskLoader(Context context) {
         // Calculate the cache sizes, we just use a reasonable number here similar to those
-        // suggested in the Android docs, 1/8th for the thumbnail cache and 1/32 of the max memory
+        // suggested in the Android docs, 1/6th for the thumbnail cache and 1/30 of the max memory
         // for icons.
-        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
-        mMaxThumbnailCacheSize = maxMemory / 8;
-        mMaxIconCacheSize = mMaxThumbnailCacheSize / 4;
+        int maxMemory = (int) Runtime.getRuntime().maxMemory();
+        mMaxThumbnailCacheSize = maxMemory / 6;
+        mMaxIconCacheSize = mMaxThumbnailCacheSize / 5;
         int iconCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
                 mMaxIconCacheSize;
         int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
                 mMaxThumbnailCacheSize;
 
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader,
-                    "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
-                    " iconCache: " + iconCacheSize);
-        }
-
         // Create the default assets
         Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         icon.eraseColor(0x00000000);
@@ -340,14 +260,7 @@
         mApplicationIconCache = new DrawableLruCache(iconCacheSize);
         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
         mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
-                mDefaultThumbnail);
-
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader,
-                    "[RecentsTaskLoader|defaultBitmaps]",
-                    "icon: " + mDefaultApplicationIcon +
-                    " default thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
-        }
+                mDefaultThumbnail, mDefaultApplicationIcon);
     }
 
     /** Initializes the recents task loader */
@@ -369,32 +282,18 @@
     }
 
     private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp) {
-        long t1 = System.currentTimeMillis();
-
         List<ActivityManager.RecentTaskInfo> tasks =
                 ssp.getRecentTasks(50, UserHandle.CURRENT.getIdentifier());
         Collections.reverse(tasks);
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TimeSystemCalls,
-                    "[RecentsTaskLoader|getRecentTasks]",
-                    "" + (System.currentTimeMillis() - t1) + "ms");
-            Console.log(Constants.Log.App.TaskDataLoader,
-                    "[RecentsTaskLoader|tasks]", "" + tasks.size());
-        }
 
         return tasks;
     }
 
     /** Reload the set of recent tasks */
     public SpaceNode reload(Context context, int preloadCount) {
-        long t1 = System.currentTimeMillis();
-
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
-        }
         RecentsConfiguration config = RecentsConfiguration.getInstance();
         Resources res = context.getResources();
-        ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
+        LinkedHashSet<Task> tasksToLoad = new LinkedHashSet<Task>();
         TaskStack stack = new TaskStack();
         SpaceNode root = new SpaceNode();
         root.setStack(stack);
@@ -404,7 +303,6 @@
         List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp);
 
         // Add each task to the task stack
-        t1 = System.currentTimeMillis();
         int taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = tasks.get(i);
@@ -434,37 +332,28 @@
 
             // Preload the specified number of apps
             if (i >= (taskCount - preloadCount)) {
-                if (Console.Enabled) {
-                    Console.log(Constants.Log.App.TaskDataLoader,
-                            "[RecentsTaskLoader|preloadTask]",
-                            "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
-                }
-
                 // Load the icon from the cache if possible
                 task.applicationIcon = mApplicationIconCache.getCheckLastActiveTime(task.key);
                 if (task.applicationIcon == null) {
                     if (isForemostTask) {
                         // We force loading the application icon for the foremost task
                         task.applicationIcon = ssp.getActivityIcon(info, task.userId);
-                        if (task.applicationIcon != null) {
-                            mApplicationIconCache.put(task.key, task.applicationIcon);
-                        } else {
+                        if (task.applicationIcon == null) {
                             task.applicationIcon = mDefaultApplicationIcon;
                         }
+                        // Even if we can't load the icon we set the default application icon into
+                        // the cache.  This will remain until the task's last active time is updated.
+                        mApplicationIconCache.put(task.key, task.applicationIcon);
                     } else {
-                        // Either the task has updated, or we haven't cached any information for the
-                        // task, so reload it
-                        tasksToForceLoad.add(task);
+                        // Either the task has changed since the last active time, or it was not
+                        // previously cached, so try and load the task anew.
+                        tasksToLoad.add(task);
                     }
                 }
 
                 // Load the thumbnail (if possible and not the foremost task, from the cache)
                 task.thumbnail = mThumbnailCache.getCheckLastActiveTime(task.key);
                 if (task.thumbnail == null) {
-                    if (Console.Enabled) {
-                        Console.log(Constants.Log.App.TaskDataLoader,
-                                "[RecentsTaskLoader|loadingTaskThumbnail]");
-                    }
                     if (isForemostTask) {
                         // We force loading the thumbnail icon for the foremost task
                         task.thumbnail = ssp.getTaskThumbnail(task.key.id);
@@ -473,37 +362,30 @@
                         } else {
                             task.thumbnail = mDefaultThumbnail;
                         }
+                        // Even if we can't load the thumbnail we set the default thumbnail into
+                        // the cache.  This will remain until the task's last active time is updated.
                         mThumbnailCache.put(task.key, task.thumbnail);
                     } else {
-                        // Either the task has updated, or we haven't cached any information for the
-                        // task, so reload it
-                        tasksToForceLoad.add(task);
+                        // Either the task has changed since the last active time, or it was not
+                        // previously cached, so try and load the task anew.
+                        tasksToLoad.add(task);
                     }
                 }
             }
 
             // Add the task to the stack
-            if (Console.Enabled) {
-                Console.log(Constants.Log.App.TaskDataLoader,
-                        "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
-            }
             stack.addTask(task);
         }
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TimeSystemCalls,
-                    "[RecentsTaskLoader|getAllTaskTopThumbnail]",
-                    "" + (System.currentTimeMillis() - t1) + "ms");
-        }
 
         // Simulate the groupings that we describe
-        stack.createSimulatedAffiliatedGroupings();
+        stack.createAffiliatedGroupings();
 
         // Start the task loader
         mLoader.start(context);
 
-        // Add all the tasks that we are force/re-loading
-        for (Task t : tasksToForceLoad) {
-            mLoadQueue.addTask(t, true);
+        // Add all the tasks that we are reloading
+        for (Task t : tasksToLoad) {
+            mLoadQueue.addTask(t);
         }
 
         // Update the package monitor with the list of packages to listen for
@@ -526,7 +408,7 @@
             stack.addTask(new Task(t.persistentId, true, t.baseIntent, t.affiliatedTaskId, null,
                     null, 0, 0, t.firstActiveTime, t.lastActiveTime, (i == (taskCount - 1))));
         }
-        stack.createSimulatedAffiliatedGroupings();
+        stack.createAffiliatedGroupings();
         return stack;
     }
 
@@ -535,12 +417,6 @@
         Drawable applicationIcon = mApplicationIconCache.get(t.key);
         Bitmap thumbnail = mThumbnailCache.get(t.key);
 
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
-                    t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
-                            " thumbnailCacheSize: " + mThumbnailCache.size());
-        }
-
         boolean requiresLoad = false;
         if (applicationIcon == null) {
             applicationIcon = mDefaultApplicationIcon;
@@ -551,30 +427,19 @@
             requiresLoad = true;
         }
         if (requiresLoad) {
-            mLoadQueue.addTask(t, false);
+            mLoadQueue.addTask(t);
         }
         t.notifyTaskDataLoaded(thumbnail, applicationIcon);
     }
 
     /** Releases the task resource data back into the pool. */
     public void unloadTaskData(Task t) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader,
-                    "[RecentsTaskLoader|unloadTask]", t +
-                    " thumbnailCacheSize: " + mThumbnailCache.size());
-        }
-
         mLoadQueue.removeTask(t);
         t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
     }
 
     /** Completely removes the resource data from the pool. */
     public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader,
-                    "[RecentsTaskLoader|deleteTask]", t);
-        }
-
         mLoadQueue.removeTask(t);
         mThumbnailCache.remove(t.key);
         mApplicationIconCache.remove(t.key);
@@ -585,9 +450,6 @@
 
     /** Stops the task loader and clears all pending tasks */
     void stopLoader() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
-        }
         mLoader.stop();
         mLoadQueue.clearTasks();
     }
@@ -608,11 +470,6 @@
      * out of memory.
      */
     public void onTrimMemory(int level) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
-                    Console.trimMemoryLevelToString(level));
-        }
-
         switch (level) {
             case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
                 // Stop the loader immediately when the UI is no longer visible
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 88e9f40..1670735 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import com.android.systemui.recents.misc.Utilities;
 
@@ -84,7 +85,7 @@
     public Drawable activityIcon;
     public String activityLabel;
     public int colorPrimary;
-    public int colorPrimaryGreyscale;
+    public boolean useLightOnPrimaryColor;
     public Bitmap thumbnail;
     public boolean isActive;
     public boolean canLockToTask;
@@ -104,7 +105,8 @@
         this.activityLabel = activityTitle;
         this.activityIcon = activityIcon;
         this.colorPrimary = colorPrimary;
-        this.colorPrimaryGreyscale = Utilities.colorToGreyscale(colorPrimary);
+        this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(colorPrimary,
+                Color.WHITE) > 3f;
         this.isActive = isActive;
         this.canLockToTask = canLockToTask;
         this.userId = userId;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 7dd15a6..e3bcff0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -320,7 +320,7 @@
     /**
      * Temporary: This method will simulate affiliation groups by
      */
-    public void createSimulatedAffiliatedGroupings() {
+    public void createAffiliatedGroupings() {
         if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) {
             HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
             // Sort all tasks by increasing firstActiveTime of the task
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FullscreenTransitionOverlayView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FullscreenTransitionOverlayView.java
index 57b8ea4..63f59be 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FullscreenTransitionOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FullscreenTransitionOverlayView.java
@@ -22,8 +22,6 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
@@ -34,9 +32,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import com.android.systemui.R;
-import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.misc.Console;
 
 
 /**
@@ -152,11 +148,6 @@
     public void prepareAnimateOnEnterRecents(Bitmap screenshot) {
         if (!mConfig.launchedFromAppWithScreenshot) return;
 
-        if (Console.Enabled) {
-            Console.logStartTracingTime(Constants.Log.App.TimeRecentsScreenshotTransition,
-                    Constants.Log.App.TimeRecentsScreenshotTransitionKey);
-        }
-
         setClipTop(0);
         setClipBottom(getMeasuredHeight());
         setDim(0);
@@ -180,11 +171,6 @@
     /** Animates this view as it enters recents */
     public void animateOnEnterRecents(ViewAnimation.TaskViewEnterContext ctx,
                                       final Runnable postAnimRunnable) {
-        if (Console.Enabled) {
-            Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
-                    Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Starting");
-        }
-
         // Cancel the current animation
         if (mEnterAnimation != null) {
             mEnterAnimation.removeAllListeners();
@@ -226,11 +212,6 @@
                         mCb.onEnterAnimationComplete();
                         // Run the given post-anim runnable
                         postAnimRunnable.run();
-
-                        if (Console.Enabled) {
-                            Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
-                                    Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Completed");
-                        }
                     }
                 });
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 99b012e..7bb6144 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -141,20 +141,12 @@
                     TaskView tv = (TaskView) stackView.getChildAt(j);
                     Task task = tv.getTask();
                     if (tv.isFocusedTask()) {
-                        if (Console.Enabled) {
-                            Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
-                                    "Found focused Task");
-                        }
                         onTaskViewClicked(stackView, tv, stack, task, false);
                         return true;
                     }
                 }
             }
         }
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
-                    "No Tasks focused");
-        }
         return false;
     }
 
@@ -191,10 +183,6 @@
 
     /** Requests all task stacks to start their enter-recents animation */
     public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
-        // Handle the case when there are no views by incrementing and decrementing after all
-        // animations are started.
-        ctx.postAnimationTrigger.increment();
-
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -203,18 +191,10 @@
                 stackView.startEnterRecentsAnimation(ctx);
             }
         }
-
-        // Handle the case when there are no views by incrementing and decrementing after all
-        // animations are started.
-        ctx.postAnimationTrigger.decrement();
     }
 
     /** Requests all task stacks to start their exit-recents animation */
     public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
-        // Handle the case when there are no views by incrementing and decrementing after all
-        // animations are started.
-        ctx.postAnimationTrigger.increment();
-
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -224,10 +204,6 @@
             }
         }
 
-        // Handle the case when there are no views by incrementing and decrementing after all
-        // animations are started.
-        ctx.postAnimationTrigger.decrement();
-
         // Notify of the exit animation
         mCb.onExitToHomeAnimationTriggered();
     }
@@ -244,12 +220,6 @@
             if (searchBar != null) {
                 mSearchBar = searchBar;
                 addView(mSearchBar);
-
-                if (Console.Enabled) {
-                    Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
-                            "" + (mSearchBar.getVisibility() == View.VISIBLE),
-                            Console.AnsiBlue);
-                }
             }
         }
     }
@@ -276,13 +246,6 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
 
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|measure]",
-                    "width: " + width + " height: " + height, Console.AnsiGreen);
-            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                    Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
-        }
-
         // Get the search bar bounds and measure the search bar layout
         if (mSearchBar != null) {
             Rect searchBarSpaceBounds = new Rect();
@@ -319,13 +282,6 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|layout]",
-                    new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
-            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
-                    Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onLayout");
-        }
-
         // Get the search bar bounds so that we lay it out
         if (mSearchBar != null) {
             Rect searchBarSpaceBounds = new Rect();
@@ -367,11 +323,6 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.MeasureAndLayout,
-                    "[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
-        }
-
         // Update the configuration with the latest system insets and trigger a relayout
         mConfig.updateSystemInsets(insets.getSystemWindowInsets());
         requestLayout();
@@ -498,11 +449,6 @@
         final Runnable launchRunnable = new Runnable() {
             @Override
             public void run() {
-                if (Console.Enabled) {
-                    Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                            Constants.Log.App.TimeRecentsLaunchKey, "preStartActivity");
-                }
-
                 if (task.isActive) {
                     // Bring an active task to the foreground
                     RecentsTaskLoader.getInstance().getSystemServicesProxy()
@@ -531,19 +477,9 @@
                     // And clean up the old task
                     onTaskViewDismissed(task);
                 }
-
-                if (Console.Enabled) {
-                    Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                            Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
-                }
             }
         };
 
-        if (Console.Enabled) {
-            Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
-                    Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
-        }
-
         // Launch the app right away if there is no task view, otherwise, animate the icon out first
         if (tv == null) {
             post(launchRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 8409227..e0298ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -28,8 +28,6 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.animation.LinearInterpolator;
-import com.android.systemui.recents.misc.Console;
-import com.android.systemui.recents.Constants;
 
 /**
  * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
@@ -178,11 +176,6 @@
     }
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.TouchEvents,
-                    "[SwipeHelper|interceptTouchEvent]",
-                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
-        }
         final int action = ev.getAction();
 
         switch (action) {
@@ -294,12 +287,6 @@
     }
 
     public boolean onTouchEvent(MotionEvent ev) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.TouchEvents,
-                    "[SwipeHelper|touchEvent]",
-                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
-        }
-
         if (!mDragging) {
             if (!onInterceptTouchEvent(ev)) {
                 return mCanCurrViewBeDimissed;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index db84962..deb9df3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -162,11 +162,10 @@
         }
         // Try and apply the system ui tint
         setBackgroundColor(t.colorPrimary);
-        mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColorGreyscale(
-                t.colorPrimaryGreyscale, mConfig.taskBarViewLightTextColor,
-                mConfig.taskBarViewDarkTextColor));
-        mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColorGreyscale(
-                t.colorPrimaryGreyscale, mLightDismissDrawable, mDarkDismissDrawable));
+        mActivityDescription.setTextColor(t.useLightOnPrimaryColor ?
+                mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor);
+        mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
+                mLightDismissDrawable : mDarkDismissDrawable);
     }
 
     /** Unbinds the bar view from the task */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 599c590..7b52163 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -167,10 +167,6 @@
         requestSynchronizeStackViewsWithModel(0);
     }
     void requestSynchronizeStackViewsWithModel(int duration) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
-                    "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
-        }
         if (!mStackViewsDirty) {
             invalidate(mStackAlgorithm.mStackRect);
         }
@@ -266,11 +262,6 @@
         if (visibleRangeOut != null) {
             visibleRangeOut[0] = frontMostVisibleIndex;
             visibleRangeOut[1] = backMostVisibleIndex;
-            if (Console.Enabled) {
-                Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
-                        "[TaskStackView|updateStackTransforms]",
-                        "Back: " + backMostVisibleIndex + " Front: " + frontMostVisibleIndex);
-            }
         }
     }
 
@@ -290,11 +281,6 @@
 
     /** Synchronizes the views with the model */
     void synchronizeStackViewsWithModel() {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
-                    "[TaskStackView|synchronizeViewsWithModel]",
-                    "mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
-        }
         if (mStackViewsDirty) {
             // Get all the task transforms
             ArrayList<Task> tasks = mStack.getTasks();
@@ -302,7 +288,6 @@
             int[] visibleRange = mTmpVisibleRange;
             updateStackTransforms(mCurrentTaskTransforms, tasks, stackScroll, visibleRange, false);
             TaskViewTransform tmpTransform = new TaskViewTransform();
-            TaskStack.GroupTaskIndex gti = new TaskStack.GroupTaskIndex();
 
             // Return all the invisible children to the pool
             HashMap<Task, TaskView> taskChildViewMap = getTaskChildViewMap();
@@ -345,16 +330,52 @@
                         mStackViewsAnimationDuration);
             }
 
-            if (Console.Enabled) {
-                Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
-                        "  [TaskStackView|viewChildren]", "" + getChildCount());
-            }
-
             mStackViewsAnimationDuration = 0;
             mStackViewsDirty = false;
         }
     }
 
+    /** Updates the clip for each of the task views. */
+    void clipTaskViews() {
+        // Update the clip on each task child
+        if (Constants.DebugFlags.App.EnableTaskStackClipping) {
+            int childCount = getChildCount();
+            for (int i = 0; i < childCount - 1; i++) {
+                TaskView tv = (TaskView) getChildAt(i);
+                TaskView nextTv = null;
+                TaskView tmpTv = null;
+                int clipBottom = 0;
+                if (tv.shouldClipViewInStack()) {
+                    // Find the next view to clip against
+                    int nextIndex = i;
+                    while (nextIndex < getChildCount()) {
+                        tmpTv = (TaskView) getChildAt(++nextIndex);
+                        if (tmpTv != null && tmpTv.shouldClipViewInStack()) {
+                            nextTv = tmpTv;
+                            break;
+                        }
+                    }
+
+                    // Clip against the next view, this is just an approximation since we are
+                    // stacked and we can make assumptions about the visibility of the this
+                    // task relative to the ones in front of it.
+                    if (nextTv != null) {
+                        // XXX: Can hash the visible rects for this run
+                        tv.getHitRect(mTmpRect);
+                        nextTv.getHitRect(mTmpRect2);
+                        clipBottom = (mTmpRect.bottom - mTmpRect2.top);
+                    }
+                }
+                tv.setClipFromBottom(clipBottom);
+            }
+        }
+        if (getChildCount() > 0) {
+            // The front most task should never be clipped
+            TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
+            tv.setClipFromBottom(0);
+        }
+    }
+
     /** Sets the current stack scroll */
     public void setStackScroll(int value) {
         mStackScroll = value;
@@ -497,11 +518,6 @@
         mMaxScroll = mStackAlgorithm.mMaxScroll;
 
         // Debug logging
-        if (Constants.Log.UI.MeasureAndLayout) {
-            Console.log("  [TaskStack|minScroll] " + mMinScroll);
-            Console.log("  [TaskStack|maxScroll] " + mMaxScroll);
-        }
-
         if (boundScrollToNewMinMax) {
             boundScroll();
         }
@@ -523,9 +539,6 @@
 
     /** Focuses the task at the specified index in the stack */
     void focusTask(int taskIndex, boolean scrollToNewPosition) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "" + taskIndex);
-        }
         if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
             mFocusedTaskIndex = taskIndex;
 
@@ -535,9 +548,6 @@
             Runnable postScrollRunnable = null;
             if (tv != null) {
                 tv.setFocusedTask();
-                if (Console.Enabled) {
-                    Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "Requesting focus");
-                }
             } else {
                 postScrollRunnable = new Runnable() {
                     @Override
@@ -546,10 +556,6 @@
                         TaskView tv = getChildViewForTask(t);
                         if (tv != null) {
                             tv.setFocusedTask();
-                            if (Console.Enabled) {
-                                Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]",
-                                        "Requesting focus after scroll animation");
-                            }
                         }
                     }
                 };
@@ -571,11 +577,6 @@
 
     /** Focuses the next task in the stack */
     void focusNextTask(boolean forward) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusNextTask]", "" +
-                    mFocusedTaskIndex);
-        }
-
         // Find the next index to focus
         int numTasks = mStack.getTaskCount();
         if (mFocusedTaskIndex < 0) {
@@ -590,24 +591,12 @@
 
     /** Enables the hw layers and increments the hw layer requirement ref count */
     void addHwLayersRefCount(String reason) {
-        if (Console.Enabled) {
-            int refCount = mHwLayersTrigger.getCount();
-            Console.log(Constants.Log.UI.HwLayers,
-                    "[TaskStackView|addHwLayersRefCount] refCount: " +
-                            refCount + "->" + (refCount + 1) + " " + reason);
-        }
         mHwLayersTrigger.increment();
     }
 
     /** Decrements the hw layer requirement ref count and disables the hw layers when we don't
         need them anymore. */
     void decHwLayersRefCount(String reason) {
-        if (Console.Enabled) {
-            int refCount = mHwLayersTrigger.getCount();
-            Console.log(Constants.Log.UI.HwLayers,
-                    "[TaskStackView|decHwLayersRefCount] refCount: " +
-                            refCount + "->" + (refCount - 1) + " " + reason);
-        }
         mHwLayersTrigger.decrement();
     }
 
@@ -636,55 +625,11 @@
 
     @Override
     public void dispatchDraw(Canvas canvas) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.Draw, "[TaskStackView|dispatchDraw]", "",
-                    Console.AnsiPurple);
-        }
         synchronizeStackViewsWithModel();
+        clipTaskViews();
         super.dispatchDraw(canvas);
     }
 
-    @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        if (Constants.DebugFlags.App.EnableTaskStackClipping) {
-            TaskView tv = (TaskView) child;
-            TaskView nextTv = null;
-            TaskView tmpTv = null;
-            if (tv.shouldClipViewInStack()) {
-                int curIndex = indexOfChild(tv);
-
-                // Find the next view to clip against
-                while (nextTv == null && curIndex < getChildCount()) {
-                    tmpTv = (TaskView) getChildAt(++curIndex);
-                    if (tmpTv != null && tmpTv.shouldClipViewInStack()) {
-                        nextTv = tmpTv;
-                    }
-                }
-
-                // Clip against the next view (if we aren't animating its alpha)
-                if (nextTv != null) {
-                    Rect curRect = tv.getClippingRect(mTmpRect);
-                    Rect nextRect = nextTv.getClippingRect(mTmpRect2);
-                    // The hit rects are relative to the task view, which needs to be offset by
-                    // the system bar height
-                    curRect.offset(0, mConfig.systemInsets.top);
-                    nextRect.offset(0, mConfig.systemInsets.top);
-                    // Compute the clip region
-                    Region clipRegion = new Region();
-                    clipRegion.op(curRect, Region.Op.UNION);
-                    clipRegion.op(nextRect, Region.Op.DIFFERENCE);
-                    // Clip the canvas
-                    int saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
-                    canvas.clipRegion(clipRegion);
-                    boolean invalidate = super.drawChild(canvas, child, drawingTime);
-                    canvas.restoreToCount(saveCount);
-                    return invalidate;
-                }
-            }
-        }
-        return super.drawChild(canvas, child, drawingTime);
-    }
-
     /** Computes the stack and task rects */
     public void computeRects(int width, int height, int insetLeft, int insetBottom) {
         // Compute the rects in the stack algorithm
@@ -703,25 +648,12 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|measure]",
-                    "width: " + width + " height: " + height +
-                            " awaitingFirstLayout: " + mAwaitingFirstLayout, Console.AnsiGreen);
-        }
 
         // Compute our stack/task rects
         Rect taskStackBounds = new Rect();
         mConfig.getTaskStackBounds(width, height, taskStackBounds);
         computeRects(width, height, taskStackBounds.left, mConfig.systemInsets.bottom);
 
-        // Debug logging
-        if (Constants.Log.UI.MeasureAndLayout) {
-            Console.log("  [TaskStack|fullRect] " + mStackAlgorithm.mRect);
-            Console.log("  [TaskStack|stackRect] " + mStackAlgorithm.mStackRect);
-            Console.log("  [TaskStack|stackRectSansPeek] " + mStackAlgorithm.mStackRectSansPeek);
-            Console.log("  [TaskStack|taskRect] " + mStackAlgorithm.mTaskRect);
-        }
-
         // If this is the first layout, then scroll to the front of the stack and synchronize the
         // stack views immediately
         if (mAwaitingFirstLayout) {
@@ -749,19 +681,6 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|layout]",
-                    "" + new Rect(left, top, right, bottom), Console.AnsiGreen);
-        }
-
-        // Debug logging
-        if (Constants.Log.UI.MeasureAndLayout) {
-            Console.log("  [TaskStack|fullRect] " + mStackAlgorithm.mRect);
-            Console.log("  [TaskStack|stackRect] " + mStackAlgorithm.mStackRect);
-            Console.log("  [TaskStack|stackRectSansPeek] " + mStackAlgorithm.mStackRectSansPeek);
-            Console.log("  [TaskStack|taskRect] " + mStackAlgorithm.mTaskRect);
-        }
-
         // Layout each of the children
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -1021,19 +940,12 @@
 
     @Override
     public TaskView createView(Context context) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
-        }
         return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
     }
 
     @Override
     public void prepareViewToEnterPool(TaskView tv) {
         Task task = tv.getTask();
-        if (Console.Enabled) {
-            Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
-                    tv.getTask() + " tv: " + tv);
-        }
 
         // Report that this tasks's data is no longer being used
         RecentsTaskLoader.getInstance().unloadTaskData(task);
@@ -1050,11 +962,6 @@
 
     @Override
     public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
-                    "isNewView: " + isNewView);
-        }
-
         // Rebind the task and request that this task's data be filled into the TaskView
         tv.onTaskBound(task);
         RecentsTaskLoader.getInstance().loadTaskData(task);
@@ -1083,10 +990,6 @@
         }
 
         // Add/attach the view to the hierarchy
-        if (Console.Enabled) {
-            Console.log(Constants.Log.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
-                    "" + insertIndex);
-        }
         if (isNewView) {
             addView(tv, insertIndex);
 
@@ -1112,11 +1015,6 @@
 
     @Override
     public void onTaskViewAppIconClicked(TaskView tv) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
-                    tv.getTask() + " is currently filtered: " + mStack.hasFilteredTasks(),
-                    Console.AnsiCyan);
-        }
         if (Constants.DebugFlags.App.EnableTaskFiltering) {
             if (mStack.hasFilteredTasks()) {
                 mStack.unfilterTasks();
@@ -1135,11 +1033,6 @@
 
     @Override
     public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
-                    task + " cb: " + mCb);
-        }
-
         // Cancel any doze triggers
         mUIDozeTrigger.stopDozing();
 
@@ -1155,6 +1048,11 @@
         mStack.removeTask(task);
     }
 
+    @Override
+    public void onTaskViewClipStateChanged(TaskView tv) {
+        invalidate(mStackAlgorithm.mStackRect);
+    }
+
     /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 908e063..9c48896 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -135,9 +135,9 @@
         // Set the y translation
         if (boundedT < 0f) {
             transformOut.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
-                    numPeekCards) * peekHeight - scaleYOffset - scaleBarYOffset);
+                    numPeekCards) * peekHeight - scaleYOffset);
         } else {
-            transformOut.translationY = (int) (boundedT * overlapHeight - scaleYOffset - scaleBarYOffset);
+            transformOut.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
         }
 
         // Set the z translation
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 15ace13..bd4ea90 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -22,7 +22,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.Constants;
 
 /* Handles touch events for a TaskStackView. */
@@ -100,12 +99,6 @@
 
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.TouchEvents,
-                    "[TaskStackViewTouchHandler|interceptTouchEvent]",
-                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
-        }
-
         // Return early if we have no children
         boolean hasChildren = (mSv.getChildCount() > 0);
         if (!hasChildren) {
@@ -186,12 +179,6 @@
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.TouchEvents,
-                    "[TaskStackViewTouchHandler|touchEvent]",
-                    Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
-        }
-
         // Short circuit if we have no children
         boolean hasChildren = (mSv.getChildCount() > 0);
         if (!hasChildren) {
@@ -290,16 +277,6 @@
                     int overscrollRange = (int) (Math.min(1f,
                             Math.abs((float) velocity / mMaximumVelocity)) *
                             Constants.Values.TaskStackView.TaskStackOverscrollRange);
-
-                    if (Console.Enabled) {
-                        Console.log(Constants.Log.UI.TouchEvents,
-                                "[TaskStackViewTouchHandler|fling]",
-                                "scroll: " + mSv.getStackScroll() + " velocity: " + velocity +
-                                        " maxVelocity: " + mMaximumVelocity +
-                                        " overscrollRange: " + overscrollRange,
-                                Console.AnsiGreen);
-                    }
-
                     // Fling scroll
                     mSv.mScroller.fling(0, mSv.getStackScroll(),
                             0, -velocity,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 5524e15..7e30047 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -46,8 +46,9 @@
     interface TaskViewCallbacks {
         public void onTaskViewAppIconClicked(TaskView tv);
         public void onTaskViewAppInfoClicked(TaskView tv);
-        public void onTaskViewClicked(TaskView tv, Task t, boolean lockToTask);
+        public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
         public void onTaskViewDismissed(TaskView tv);
+        public void onTaskViewClipStateChanged(TaskView tv);
     }
 
     RecentsConfiguration mConfig;
@@ -65,7 +66,7 @@
     boolean mIsFocused;
     boolean mIsStub;
     boolean mClipViewInStack;
-    Rect mTmpRect = new Rect();
+    int mClipFromBottom;
     Paint mLayerPaint = new Paint();
 
     TaskThumbnailView mThumbnailView;
@@ -118,7 +119,9 @@
         setOutlineProvider(new ViewOutlineProvider() {
             @Override
             public boolean getOutline(View view, Outline outline) {
-                int height = getHeight() - mMaxFooterHeight + mFooterHeight;
+                // The current height is measured with the footer, so account for the footer height
+                // and the current clip (in the stack)
+                int height = getMeasuredHeight() - mClipFromBottom - mMaxFooterHeight + mFooterHeight;
                 outline.setRoundRect(0, 0, getWidth(), height,
                         mConfig.taskViewRoundedCornerRadiusPx);
                 return true;
@@ -172,11 +175,6 @@
 
     /** Synchronizes this view's properties with the task's transform */
     void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) {
-        if (Console.Enabled) {
-            Console.log(Constants.Log.UI.Draw, "[TaskView|updateViewPropertiesToTaskTransform]",
-                    "duration: " + duration, Console.AnsiPurple);
-        }
-
         // Update the bar view
         mBarView.updateViewPropertiesToTaskTransform(toTransform, duration);
 
@@ -483,15 +481,6 @@
         mBarView.setNoUserInteractionState();
     }
 
-    /** Returns the rect we want to clip (it may not be the full rect) */
-    Rect getClippingRect(Rect outRect) {
-        getHitRect(outRect);
-        // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
-        outRect.right = outRect.left + mThumbnailView.getRight();
-        outRect.bottom = outRect.top + mThumbnailView.getBottom();
-        return outRect;
-    }
-
     /** Enable the hw layers on this task view */
     void enableHwLayers() {
         mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint);
@@ -506,7 +495,7 @@
         mLockToAppButtonView.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
     }
 
-    /** Sets the stubbed state of this task view. */
+    /** Sets the stubbed state of this task view.
     void setStubState(boolean isStub) {
         if (!mIsStub && isStub) {
             // This is now a stub task view, so clip to the bar height, hide the thumbnail
@@ -519,7 +508,7 @@
             mThumbnailView.setVisibility(View.VISIBLE);
         }
         mIsStub = isStub;
-    }
+    } */
 
     /**
      * Returns whether this view should be clipped, or any views below should clip against this
@@ -533,19 +522,26 @@
     void setClipViewInStack(boolean clip) {
         if (clip != mClipViewInStack) {
             mClipViewInStack = clip;
-            if (getParent() instanceof View) {
-                getHitRect(mTmpRect);
-                ((View) getParent()).invalidate(mTmpRect);
-            }
+            mCb.onTaskViewClipStateChanged(this);
+        }
+    }
+
+    void setClipFromBottom(int clipFromBottom) {
+        clipFromBottom = Math.max(0, Math.min(getMeasuredHeight(), clipFromBottom));
+        if (mClipFromBottom != clipFromBottom) {
+            mClipFromBottom = clipFromBottom;
+            invalidateOutline();
         }
     }
 
     /** Sets the footer height. */
-    public void setFooterHeight(int height) {
-        mFooterHeight = height;
-        invalidateOutline();
-        invalidate(0, getMeasuredHeight() - mMaxFooterHeight, getMeasuredWidth(),
-                getMeasuredHeight());
+    public void setFooterHeight(int footerHeight) {
+        if (footerHeight != mFooterHeight) {
+            mFooterHeight = footerHeight;
+            invalidateOutline();
+            invalidate(0, getMeasuredHeight() - mMaxFooterHeight, getMeasuredWidth(),
+                    getMeasuredHeight());
+        }
     }
 
     /** Gets the footer height. */
@@ -677,6 +673,7 @@
         mTask = t;
         mTask.setCallbacks(this);
         if (getMeasuredWidth() == 0) {
+            // If we haven't yet measured, we should just set the footer height with any animation
             animateFooterVisibility(t.canLockToTask, 0, 0);
         } else {
             animateFooterVisibility(t.canLockToTask, mConfig.taskViewLockToAppLongAnimDuration, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index ad2cf75..0c5d2a5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -908,6 +908,9 @@
 
             if (mDialog != null) {
                 mDialog.show();
+                if (mCallback != null) {
+                    mCallback.onVisible(true);
+                }
             }
         }
 
@@ -1160,6 +1163,9 @@
                         mDialog.dismiss();
                         clearRemoteStreamController();
                         mActiveStreamType = -1;
+                        if (mCallback != null) {
+                            mCallback.onVisible(false);
+                        }
                     }
                 }
                 synchronized (sConfirmSafeVolumeLock) {
@@ -1262,5 +1268,6 @@
     public interface Callback {
         void onZenSettings();
         void onInteraction();
+        void onVisible(boolean visible);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index e4f5870..375f94c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -99,6 +99,13 @@
                     kvm.userActivity();
                 }
             }
+
+            @Override
+            public void onVisible(boolean visible) {
+                if (mAudioManager != null && mVolumeController != null) {
+                    mAudioManager.notifyVolumeControllerVisible(mVolumeController, visible);
+                }
+            }
         });
         mDialogPanel = mPanel;
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index adfa1f2..f431fdb 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -49,6 +49,9 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionLegacyHelper;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -205,6 +208,8 @@
 
     private Drawable mBackgroundDrawable;
 
+    private float mElevation;
+
     private int mFrameResource = 0;
 
     private int mTextColor = 0;
@@ -224,6 +229,7 @@
     private boolean mClosingActionMenu;
 
     private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
+    private MediaController mMediaController;
 
     private AudioManager mAudioManager;
     private KeyguardManager mKeyguardManager;
@@ -1688,15 +1694,42 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_DOWN: {
+                int direction = keyCode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE
+                        : AudioManager.ADJUST_LOWER;
+                // If we have a session send it the volume command, otherwise
+                // use the suggested stream.
+                if (mMediaController != null) {
+                    mMediaController.adjustVolumeBy(direction, AudioManager.FLAG_SHOW_UI);
+                } else {
+                    MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
+                            mVolumeControlStreamType, direction, AudioManager.FLAG_SHOW_UI);
+                }
+                return true;
+            }
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                // Similar code is in PhoneFallbackEventHandler in case the window
-                // doesn't have one of these.  In this case, we execute it here and
-                // eat the event instead, because we have mVolumeControlStreamType
-                // and they don't.
                 getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
                 return true;
             }
+            // These are all the recognized media key codes in
+            // KeyEvent.isMediaKey()
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+                if (mMediaController != null) {
+                    if (mMediaController.dispatchMediaButtonEvent(event)) {
+                        return true;
+                    }
+                }
+            }
 
             case KeyEvent.KEYCODE_MENU: {
                 onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
@@ -1750,7 +1783,19 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_DOWN: {
+                // If we have a session send it the volume command, otherwise
+                // use the suggested stream.
+                if (mMediaController != null) {
+                    mMediaController.adjustVolumeBy(0, AudioManager.FLAG_PLAY_SOUND
+                            | AudioManager.FLAG_VIBRATE);
+                } else {
+                    MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
+                            mVolumeControlStreamType, 0,
+                            AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE);
+                }
+                return true;
+            }
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 // Similar code is in PhoneFallbackEventHandler in case the window
                 // doesn't have one of these.  In this case, we execute it here and
@@ -1759,6 +1804,25 @@
                 getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
                 return true;
             }
+            // These are all the recognized media key codes in
+            // KeyEvent.isMediaKey()
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+                if (mMediaController != null) {
+                    if (mMediaController.dispatchMediaButtonEvent(event)) {
+                        return true;
+                    }
+                }
+            }
 
             case KeyEvent.KEYCODE_MENU: {
                 onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
@@ -3189,6 +3253,7 @@
                             + Integer.toHexString(mFrameResource));
                 }
             }
+            mElevation = a.getDimension(com.android.internal.R.styleable.Window_windowElevation, 0);
             mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);
         }
 
@@ -3278,28 +3343,31 @@
         // Remaining setup -- of background and title -- that only applies
         // to top-level windows.
         if (getContainer() == null) {
-            Drawable drawable = mBackgroundDrawable;
+            final Drawable background;
             if (mBackgroundResource != 0) {
-                drawable = getContext().getDrawable(mBackgroundResource);
+                background = getContext().getDrawable(mBackgroundResource);
+            } else {
+                background = mBackgroundDrawable;
             }
-            mDecor.setWindowBackground(drawable);
-            drawable = null;
+            mDecor.setWindowBackground(background);
+
+            final Drawable frame;
             if (mFrameResource != 0) {
-                drawable = getContext().getDrawable(mFrameResource);
+                frame = getContext().getDrawable(mFrameResource);
+            } else {
+                frame = null;
             }
-            mDecor.setWindowFrame(drawable);
+            mDecor.setWindowFrame(frame);
 
-            // System.out.println("Text=" + Integer.toHexString(mTextColor) +
-            // " Sel=" + Integer.toHexString(mTextSelectedColor) +
-            // " Title=" + Integer.toHexString(mTitleColor));
-
-            if (mTitleColor == 0) {
-                mTitleColor = mTextColor;
-            }
+            mDecor.setElevation(mElevation);
 
             if (mTitle != null) {
                 setTitle(mTitle);
             }
+
+            if (mTitleColor == 0) {
+                mTitleColor = mTextColor;
+            }
             setTitleColor(mTitleColor);
         }
 
@@ -3773,6 +3841,16 @@
         return mVolumeControlStreamType;
     }
 
+    @Override
+    public void setMediaController(MediaController controller) {
+        mMediaController = controller;
+    }
+
+    @Override
+    public MediaController getMediaController() {
+        return mMediaController;
+    }
+
     private boolean isTranslucent() {
         TypedArray a = getWindowStyle();
         return a.getBoolean(a.getResourceId(
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 5bfde4d..c3a9dbe 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3922,6 +3922,11 @@
                                 break;
                         }
 
+                        // Is it a *file* we need to drop?
+                        if (!isRestorableFile(info)) {
+                            okay = false;
+                        }
+
                         // If the policy is satisfied, go ahead and set up to pipe the
                         // data to the agent.
                         if (DEBUG && okay && mAgent != null) {
@@ -4082,9 +4087,9 @@
                             }
                         }
 
-                        // Problems setting up the agent communication, or an already-
-                        // ignored package: skip to the next tar stream entry by
-                        // reading and discarding this file.
+                        // Problems setting up the agent communication, an explicitly
+                        // dropped file, or an already-ignored package: skip to the
+                        // next stream entry by reading and discarding this file.
                         if (!okay) {
                             if (DEBUG) Slog.d(TAG, "[discarding file content]");
                             long bytesToConsume = (info.size + 511) & ~511;
@@ -4691,6 +4696,31 @@
             return info;
         }
 
+        private boolean isRestorableFile(FileMetadata info) {
+            if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) {
+                if (MORE_DEBUG) {
+                    Slog.i(TAG, "Dropping cache file path " + info.path);
+                }
+                return false;
+            }
+
+            if (FullBackup.ROOT_TREE_TOKEN.equals(info.domain)) {
+                // It's possible this is "no-backup" dir contents in an archive stream
+                // produced on a device running a version of the OS that predates that
+                // API.  Respect the no-backup intention and don't let the data get to
+                // the app.
+                if (info.path.startsWith("no_backup/")) {
+                    if (MORE_DEBUG) {
+                        Slog.i(TAG, "Dropping no_backup file path " + info.path);
+                    }
+                    return false;
+                }
+            }
+
+            // Otherwise we think this file is good to go
+            return true;
+        }
+
         private void HEXLOG(byte[] block) {
             int offset = 0;
             int todo = block.length;
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 8222155..b3419c1 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -62,6 +62,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
@@ -70,6 +71,7 @@
 import android.telephony.SmsMessage;
 import android.telephony.TelephonyManager;
 import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.NtpTrustedTime;
 
@@ -85,6 +87,8 @@
 import java.util.Map.Entry;
 import java.util.Properties;
 
+import libcore.io.IoUtils;
+
 /**
  * A GPS implementation of LocationProvider used by LocationManager.
  *
@@ -201,7 +205,9 @@
     private static final int AGPS_SETID_TYPE_IMSI = 1;
     private static final int AGPS_SETID_TYPE_MSISDN = 2;
 
-    private static final String PROPERTIES_FILE = "/etc/gps.conf";
+    private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
+    private static final String PROPERTIES_FILE_SUFFIX = ".conf";
+    private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
 
     private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
     private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
@@ -441,6 +447,44 @@
         return native_is_supported();
     }
 
+    private boolean loadPropertiesFile(String filename) {
+        mProperties = new Properties();
+        try {
+            File file = new File(filename);
+            FileInputStream stream = null;
+            try {
+                stream = new FileInputStream(file);
+                mProperties.load(stream);
+            } finally {
+                IoUtils.closeQuietly(stream);
+            }
+
+            mSuplServerHost = mProperties.getProperty("SUPL_HOST");
+            String portString = mProperties.getProperty("SUPL_PORT");
+            if (mSuplServerHost != null && portString != null) {
+                try {
+                    mSuplServerPort = Integer.parseInt(portString);
+                } catch (NumberFormatException e) {
+                    Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
+                }
+            }
+
+            mC2KServerHost = mProperties.getProperty("C2K_HOST");
+            portString = mProperties.getProperty("C2K_PORT");
+            if (mC2KServerHost != null && portString != null) {
+                try {
+                    mC2KServerPort = Integer.parseInt(portString);
+                } catch (NumberFormatException e) {
+                    Log.e(TAG, "unable to parse C2K_PORT: " + portString);
+                }
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Could not open GPS configuration file " + filename);
+            return false;
+        }
+        return true;
+    }
+
     public GpsLocationProvider(Context context, ILocationManager ilocationManager,
             Looper looper) {
         mContext = context;
@@ -469,34 +513,15 @@
         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                 BatteryStats.SERVICE_NAME));
 
-        mProperties = new Properties();
-        try {
-            File file = new File(PROPERTIES_FILE);
-            FileInputStream stream = new FileInputStream(file);
-            mProperties.load(stream);
-            stream.close();
+        boolean propertiesLoaded = false;
+        final String gpsHardware = SystemProperties.get("ro.hardware.gps");
+        if (!TextUtils.isEmpty(gpsHardware)) {
+            final String propFilename = PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
+            propertiesLoaded = loadPropertiesFile(propFilename);
+        }
 
-            mSuplServerHost = mProperties.getProperty("SUPL_HOST");
-            String portString = mProperties.getProperty("SUPL_PORT");
-            if (mSuplServerHost != null && portString != null) {
-                try {
-                    mSuplServerPort = Integer.parseInt(portString);
-                } catch (NumberFormatException e) {
-                    Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
-                }
-            }
-
-            mC2KServerHost = mProperties.getProperty("C2K_HOST");
-            portString = mProperties.getProperty("C2K_PORT");
-            if (mC2KServerHost != null && portString != null) {
-                try {
-                    mC2KServerPort = Integer.parseInt(portString);
-                } catch (NumberFormatException e) {
-                    Log.e(TAG, "unable to parse C2K_PORT: " + portString);
-                }
-            }
-        } catch (IOException e) {
-            Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
+        if (!propertiesLoaded) {
+            loadPropertiesFile(DEFAULT_PROPERTIES_FILE);
         }
 
         // construct handler, listen for events
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 341c7a9..01a21f4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -505,16 +505,19 @@
                     || state.getState() == PlaybackState.STATE_FAST_FORWARDING
                     || state.getState() == PlaybackState.STATE_REWINDING) {
                 long updateTime = state.getLastPositionUpdateTime();
+                long currentTime = SystemClock.elapsedRealtime();
                 if (updateTime > 0) {
-                    long position = (long) (state.getPlaybackRate()
-                            * (SystemClock.elapsedRealtime() - updateTime)) + state.getPosition();
+                    long position = (long) (state.getPlaybackSpeed()
+                            * (currentTime - updateTime)) + state.getPosition();
                     if (duration >= 0 && position > duration) {
                         position = duration;
                     } else if (position < 0) {
                         position = 0;
                     }
-                    result = new PlaybackState(state);
-                    result.setState(state.getState(), position, state.getPlaybackRate());
+                    PlaybackState.Builder builder = new PlaybackState.Builder(state);
+                    builder.setState(state.getState(), position, state.getPlaybackSpeed(),
+                            currentTime);
+                    result = builder.build();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/KeySetHandle.java b/services/core/java/com/android/server/pm/KeySetHandle.java
new file mode 100644
index 0000000..640feb3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/KeySetHandle.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+    * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+     *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.os.Binder;
+
+public class KeySetHandle extends Binder {
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index c19951f..37bedf3 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -16,7 +16,6 @@
 
 package com.android.server.pm;
 
-import android.content.pm.KeySet;
 import android.content.pm.PackageParser;
 import android.os.Binder;
 import android.util.ArraySet;
@@ -52,7 +51,7 @@
     /** Sentinel value returned when public key is not found. */
     protected static final long PUBLIC_KEY_NOT_FOUND = -1;
 
-    private final LongSparseArray<KeySet> mKeySets;
+    private final LongSparseArray<KeySetHandle> mKeySets;
 
     private final LongSparseArray<PublicKey> mPublicKeys;
 
@@ -65,7 +64,7 @@
     private static long lastIssuedKeyId = 0;
 
     public KeySetManagerService(Map<String, PackageSetting> packages) {
-        mKeySets = new LongSparseArray<KeySet>();
+        mKeySets = new LongSparseArray<KeySetHandle>();
         mPublicKeys = new LongSparseArray<PublicKey>();
         mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
         mPackages = packages;
@@ -82,7 +81,7 @@
      *
      * Note that this can return true for multiple KeySets.
      */
-    public boolean packageIsSignedByLPr(String packageName, KeySet ks) {
+    public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) {
         PackageSetting pkg = mPackages.get(packageName);
         if (pkg == null) {
             throw new NullPointerException("Invalid package name");
@@ -91,16 +90,42 @@
             throw new NullPointerException("Package has no KeySet data");
         }
         long id = getIdByKeySetLPr(ks);
+        if (id == KEYSET_NOT_FOUND) {
+                return false;
+        }
         return pkg.keySetData.packageIsSignedBy(id);
     }
 
     /**
+     * Determine if a package is signed by the given KeySet.
+     *
+     * Returns false if the package was not signed by all the
+     * keys in the KeySet, or if the package was signed by keys
+     * not in the KeySet.
+     *
+     * Note that this can return only for one KeySet.
+     */
+    public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) {
+        PackageSetting pkg = mPackages.get(packageName);
+        if (pkg == null) {
+            throw new NullPointerException("Invalid package name");
+        }
+        if (pkg.keySetData == null
+            || pkg.keySetData.getProperSigningKeySet()
+            == PackageKeySetData.KEYSET_UNASSIGNED) {
+            throw new NullPointerException("Package has no KeySet data");
+        }
+        long id = getIdByKeySetLPr(ks);
+        return pkg.keySetData.getProperSigningKeySet() == id;
+    }
+
+    /**
      * This informs the system that the given package has defined a KeySet
      * in its manifest that a) contains the given keys and b) is named
      * alias by that package.
      */
     public void addDefinedKeySetToPackageLPw(String packageName,
-            Set<PublicKey> keys, String alias) {
+            ArraySet<PublicKey> keys, String alias) {
         if ((packageName == null) || (keys == null) || (alias == null)) {
             Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
             return;
@@ -110,7 +135,7 @@
             throw new NullPointerException("Unknown package");
         }
         // Add to KeySets, then to package
-        KeySet ks = addKeySetLPw(keys);
+        KeySetHandle ks = addKeySetLPw(keys);
         long id = getIdByKeySetLPr(ks);
         pkg.keySetData.addDefinedKeySet(id, alias);
     }
@@ -137,19 +162,18 @@
      * was signed by the provided KeySet.
      */
     public void addSigningKeySetToPackageLPw(String packageName,
-            Set<PublicKey> signingKeys) {
+            ArraySet<PublicKey> signingKeys) {
         if ((packageName == null) || (signingKeys == null)) {
             Slog.w(TAG, "Got null argument for a signing keyset, ignoring!");
             return;
         }
         // add the signing KeySet
-        KeySet ks = addKeySetLPw(signingKeys);
+        KeySetHandle ks = addKeySetLPw(signingKeys);
         long id = getIdByKeySetLPr(ks);
-        Set<Long> publicKeyIds = mKeySetMapping.get(id);
+        ArraySet<Long> publicKeyIds = mKeySetMapping.get(id);
         if (publicKeyIds == null) {
             throw new NullPointerException("Got invalid KeySet id");
         }
-
         // attach it to the package
         PackageSetting pkg = mPackages.get(packageName);
         if (pkg == null) {
@@ -160,7 +184,7 @@
         // KeySet id to the package's signing KeySets
         for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
             long keySetID = mKeySets.keyAt(keySetIndex);
-            Set<Long> definedKeys = mKeySetMapping.get(keySetID);
+            ArraySet<Long> definedKeys = mKeySetMapping.get(keySetID);
             if (publicKeyIds.containsAll(definedKeys)) {
                 pkg.keySetData.addSigningKeySet(keySetID);
             }
@@ -171,9 +195,9 @@
      * Fetches the stable identifier associated with the given KeySet. Returns
      * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
      */
-    private long getIdByKeySetLPr(KeySet ks) {
+    private long getIdByKeySetLPr(KeySetHandle ks) {
         for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
-            KeySet value = mKeySets.valueAt(keySetIndex);
+            KeySetHandle value = mKeySets.valueAt(keySetIndex);
             if (ks.equals(value)) {
                 return mKeySets.keyAt(keySetIndex);
             }
@@ -187,25 +211,24 @@
      * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't
      * identify a {@link KeySet}.
      */
-    public KeySet getKeySetByIdLPr(long id) {
+    public KeySetHandle getKeySetByIdLPr(long id) {
         return mKeySets.get(id);
     }
 
     /**
-     * Fetches the {@link KeySet} that a given package refers to by the provided alias.
-     *
-     * @throws IllegalArgumentException if the package has no keyset data.
-     * @throws NullPointerException if the package is unknown.
+     * Fetches the {@link KeySetHandle} that a given package refers to by the
+     * provided alias. Returns null if the package is unknown or does not have a
+     * KeySet corresponding to that alias.
      */
-    public KeySet getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
+    public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
         PackageSetting p = mPackages.get(packageName);
-        if (p == null) {
-            throw new NullPointerException("Unknown package");
+        if (p == null || p.keySetData == null) {
+                return null;
         }
-        if (p.keySetData == null) {
-            throw new IllegalArgumentException("Package has no keySet data");
+        Long keySetId = p.keySetData.getAliases().get(alias);
+        if (keySetId == null) {
+            throw new IllegalArgumentException("Unknown KeySet alias: " + alias);
         }
-        long keySetId = p.keySetData.getAliases().get(alias);
         return mKeySets.get(keySetId);
     }
 
@@ -214,7 +237,7 @@
      * KeySet id.
      *
      * Returns {@code null} if the identifier doesn't
-     * identify a {@link KeySet}.
+     * identify a {@link KeySetHandle}.
      */
     public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) {
         if(mKeySetMapping.get(id) == null) {
@@ -228,36 +251,32 @@
     }
 
     /**
-     * Fetches all the known {@link KeySet KeySets} that signed the given
+     * Fetches the proper {@link KeySetHandle KeySet} that signed the given
      * package.
      *
      * @throws IllegalArgumentException if the package has no keyset data.
      * @throws NullPointerException if the package is unknown.
      */
-    public Set<KeySet> getSigningKeySetsByPackageNameLPr(String packageName) {
-        Set<KeySet> signingKeySets = new ArraySet<KeySet>();
+    public KeySetHandle  getSigningKeySetByPackageNameLPr(String packageName) {
         PackageSetting p = mPackages.get(packageName);
-        if (p == null) {
-            throw new NullPointerException("Unknown package");
+        if (p == null
+            || p.keySetData == null
+            || p.keySetData.getProperSigningKeySet()
+            == PackageKeySetData.KEYSET_UNASSIGNED) {
+            return null;
         }
-        if (p.keySetData == null || p.keySetData.getSigningKeySets() == null) {
-            throw new IllegalArgumentException("Package has no keySet data");
-        }
-        for (long l : p.keySetData.getSigningKeySets()) {
-            signingKeySets.add(mKeySets.get(l));
-        }
-        return signingKeySets;
+        return mKeySets.get(p.keySetData.getProperSigningKeySet());
     }
 
     /**
-     * Fetches all the known {@link KeySet KeySets} that may upgrade the given
+     * Fetches all the known {@link KeySetHandle KeySets} that may upgrade the given
      * package.
      *
      * @throws IllegalArgumentException if the package has no keyset data.
      * @throws NullPointerException if the package is unknown.
      */
-    public ArraySet<KeySet> getUpgradeKeySetsByPackageNameLPr(String packageName) {
-        ArraySet<KeySet> upgradeKeySets = new ArraySet<KeySet>();
+    public ArraySet<KeySetHandle> getUpgradeKeySetsByPackageNameLPr(String packageName) {
+        ArraySet<KeySetHandle> upgradeKeySets = new ArraySet<KeySetHandle>();
         PackageSetting p = mPackages.get(packageName);
         if (p == null) {
             throw new NullPointerException("Unknown package");
@@ -287,7 +306,7 @@
      *
      * Throws if the provided set is {@code null}.
      */
-    private KeySet addKeySetLPw(Set<PublicKey> keys) {
+    private KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) {
         if (keys == null) {
             throw new NullPointerException("Provided keys cannot be null");
         }
@@ -305,7 +324,7 @@
         }
 
         // create the KeySet object
-        KeySet ks = new KeySet(new Binder());
+        KeySetHandle ks = new KeySetHandle();
         // get the first unoccupied slot in mKeySets
         long id = getFreeKeySetIDLPw();
         // add the KeySet object to it
@@ -318,7 +337,7 @@
             if (p.keySetData != null) {
                 long pProperSigning = p.keySetData.getProperSigningKeySet();
                 if (pProperSigning != PackageKeySetData.KEYSET_UNASSIGNED) {
-                    Set<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
+                    ArraySet<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
                     if (pSigningKeys.containsAll(addedKeyIds)) {
                         p.keySetData.addSigningKeySet(id);
                     }
@@ -353,7 +372,7 @@
      */
     private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) {
         for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
-            Set<Long> value = mKeySetMapping.valueAt(keyMapIndex);
+            ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex);
             if (value.equals(publicKeyIds)) {
                 return mKeySetMapping.keyAt(keyMapIndex);
             }
@@ -582,7 +601,7 @@
         serializer.startTag(null, "keysets");
         for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
             long id = mKeySetMapping.keyAt(keySetIndex);
-            Set<Long> keys = mKeySetMapping.valueAt(keySetIndex);
+            ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex);
             serializer.startTag(null, "keyset");
             serializer.attribute(null, "identifier", Long.toString(id));
             for (long keyId : keys) {
@@ -662,7 +681,7 @@
             final String tagName = parser.getName();
             if (tagName.equals("keyset")) {
                 currentKeySetId = readIdentifierLPw(parser);
-                mKeySets.put(currentKeySetId, new KeySet(new Binder()));
+                mKeySets.put(currentKeySetId, new KeySetHandle());
                 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
             } else if (tagName.equals("key-id")) {
                 long id = readIdentifierLPw(parser);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c399fa2..41ab66a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -177,7 +177,8 @@
     @Override
     public void setClientProgress(int progress) {
         mClientProgress = progress;
-        mProgress = MathUtils.constrain((mClientProgress * 8 * 100) / (params.progressMax * 10), 0, 80);
+        mProgress = MathUtils.constrain(
+                (int) (((float) mClientProgress) / ((float) params.progressMax)) * 80, 0, 80);
         mCallback.onSessionProgress(this, mProgress);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 101ef92..cfba19c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9331,14 +9331,18 @@
                 return false;
             } else {
                 final File beforeCodeFile = codeFile;
-                final File afterCodeFile = new File(mAppInstallDir,
-                        getNextCodePath(oldCodePath, pkg.packageName, null));
+                final File afterCodeFile = getNextCodePath(pkg.packageName);
 
                 Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
-                if (!beforeCodeFile.renameTo(afterCodeFile)) {
+                try {
+                    Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
+                } catch (ErrnoException e) {
+                    Slog.d(TAG, "Failed to rename", e);
                     return false;
                 }
+
                 if (!SELinux.restoreconRecursive(afterCodeFile)) {
+                    Slog.d(TAG, "Failed to restorecon");
                     return false;
                 }
 
@@ -9811,6 +9815,16 @@
         return prefix + idxStr;
     }
 
+    private File getNextCodePath(String packageName) {
+        int suffix = 1;
+        File result;
+        do {
+            result = new File(mAppInstallDir, packageName + "-" + suffix);
+            suffix++;
+        } while (result.exists());
+        return result;
+    }
+
     // Utility method used to ignore ADD/REMOVE events
     // by directory observer.
     private static boolean ignoreCodePath(String fullPathStr) {
@@ -13255,4 +13269,83 @@
         }
         return mUserNeedsBadging.valueAt(index);
     }
+
+    @Override
+    public KeySetHandle getKeySetByAlias(String packageName, String alias) {
+        if (packageName == null || alias == null) {
+            return null;
+        }
+        synchronized(mPackages) {
+            final PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (pkg.applicationInfo.uid != Binder.getCallingUid()
+                    && Process.SYSTEM_UID != Binder.getCallingUid()) {
+                throw new SecurityException("May not access KeySets defined by"
+                        + " aliases in other applications.");
+            }
+            KeySetManagerService ksms = mSettings.mKeySetManagerService;
+            return ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias);
+        }
+    }
+
+    @Override
+    public KeySetHandle getSigningKeySet(String packageName) {
+        if (packageName == null) {
+            return null;
+        }
+        synchronized(mPackages) {
+            final PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (pkg.applicationInfo.uid != Binder.getCallingUid()
+                    && Process.SYSTEM_UID != Binder.getCallingUid()) {
+                throw new SecurityException("May not access signing KeySet of other apps.");
+            }
+            KeySetManagerService ksms = mSettings.mKeySetManagerService;
+            return ksms.getSigningKeySetByPackageNameLPr(packageName);
+        }
+    }
+
+    @Override
+    public boolean isPackageSignedByKeySet(String packageName, IBinder ks) {
+        if (packageName == null || ks == null) {
+            return false;
+        }
+        synchronized(mPackages) {
+            final PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (ks instanceof KeySetHandle) {
+                KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ks);
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isPackageSignedByKeySetExactly(String packageName, IBinder ks) {
+        if (packageName == null || ks == null) {
+            return false;
+        }
+        synchronized(mPackages) {
+            final PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (ks instanceof KeySetHandle) {
+                KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ks);
+            }
+            return false;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 8387b65..b24072f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -717,10 +717,10 @@
             float top = w.mFrame.top + w.mYOffset;
 
             // Adjust for surface insets.
-            width += attrs.shadowInsets.left + attrs.shadowInsets.right;
-            height += attrs.shadowInsets.top + attrs.shadowInsets.bottom;
-            left -= attrs.shadowInsets.left;
-            top -= attrs.shadowInsets.top;
+            width += attrs.surfaceInsets.left + attrs.surfaceInsets.right;
+            height += attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
+            left -= attrs.surfaceInsets.left;
+            top -= attrs.surfaceInsets.top;
 
             if (DEBUG_VISIBILITY) {
                 Slog.v(TAG, "Creating surface in session "
@@ -1140,19 +1140,12 @@
 
     void applyDecorRect(final Rect decorRect) {
         final WindowState w = mWin;
-        int width = w.mFrame.width();
-        int height = w.mFrame.height();
+        final int width = w.mFrame.width();
+        final int height = w.mFrame.height();
 
         // Compute the offset of the window in relation to the decor rect.
-        int left = w.mXOffset + w.mFrame.left;
-        int top = w.mYOffset + w.mFrame.top;
-
-        // Adjust for surface insets.
-        final WindowManager.LayoutParams attrs = w.mAttrs;
-        width += attrs.shadowInsets.left + attrs.shadowInsets.right;
-        height += attrs.shadowInsets.top + attrs.shadowInsets.bottom;
-        left -= attrs.shadowInsets.left;
-        top -= attrs.shadowInsets.top;
+        final int left = w.mXOffset + w.mFrame.left;
+        final int top = w.mYOffset + w.mFrame.top;
 
         // Initialize the decor rect to the entire frame.
         w.mSystemDecorRect.set(0, 0, width, height);
@@ -1182,7 +1175,6 @@
         if (displayContent == null) {
             return;
         }
-        DisplayInfo displayInfo = displayContent.getDisplayInfo();
 
         // Need to recompute a new system decor rect each time.
         if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -1192,6 +1184,7 @@
         } else if (!w.isDefaultDisplay()) {
             // On a different display there is no system decor.  Crop the window
             // by the screen boundaries.
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
             w.mSystemDecorRect.intersect(-w.mCompatFrame.left, -w.mCompatFrame.top,
                     displayInfo.logicalWidth - w.mCompatFrame.left,
@@ -1202,44 +1195,52 @@
             // windows need to be cropped by the screen, so they don't cover
             // the universe background.
             if (mAnimator.mUniverseBackground == null) {
-                w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(),
-                        w.mCompatFrame.height());
+                w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
             } else {
                 applyDecorRect(mService.mScreenRect);
             }
         } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
                 || w.mDecorFrame.isEmpty()) {
             // The universe background isn't cropped, nor windows without policy decor.
-            w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(),
-                    w.mCompatFrame.height());
+            w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
         } else {
             // Crop to the system decor specified by policy.
             applyDecorRect(w.mDecorFrame);
         }
 
-        // By default, the clip rect is the system decor rect
-        Rect clipRect = w.mSystemDecorRect;
-        if (mHasClipRect) {
+        // By default, the clip rect is the system decor.
+        final Rect clipRect = mTmpClipRect;
+        clipRect.set(w.mSystemDecorRect);
 
-            // If we have an animated clip rect, intersect it with the system decor rect
-            // NOTE: We are adding a temporary workaround due to the status bar not always reporting
-            // the correct system decor rect.  In such cases, we take into account the specified
-            // content insets as well.
-            int offsetTop = Math.max(w.mSystemDecorRect.top, w.mContentInsets.top);
-            mTmpClipRect.set(w.mSystemDecorRect);
-            // Don't apply the workaround to apps explicitly requesting fullscreen layout.
+        // Expand the clip rect for surface insets.
+        final WindowManager.LayoutParams attrs = w.mAttrs;
+        clipRect.left -= attrs.surfaceInsets.left;
+        clipRect.top -= attrs.surfaceInsets.top;
+        clipRect.right += attrs.surfaceInsets.right;
+        clipRect.bottom += attrs.surfaceInsets.bottom;
+
+        // If we have an animated clip rect, intersect it with the clip rect.
+        if (mHasClipRect) {
+            // NOTE: We are adding a temporary workaround due to the status bar
+            // not always reporting the correct system decor rect. In such
+            // cases, we take into account the specified content insets as well.
             if ((w.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
                     == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) {
-                mTmpClipRect.intersect(mClipRect);
+                // Don't apply the workaround to apps explicitly requesting
+                // fullscreen layout.
+                clipRect.intersect(mClipRect);
             } else {
-                mTmpClipRect.offset(0, -offsetTop);
-                mTmpClipRect.intersect(mClipRect);
-                mTmpClipRect.offset(0, offsetTop);
+                final int offsetTop = Math.max(clipRect.top, w.mContentInsets.top);
+                clipRect.offset(0, -offsetTop);
+                clipRect.intersect(mClipRect);
+                clipRect.offset(0, offsetTop);
             }
-            clipRect = mTmpClipRect;
-
         }
 
+        // The clip rect was generated assuming (0,0) as the window origin,
+        // so we need to translate to match the actual surface coordinates.
+        clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
+
         if (!clipRect.equals(mLastClipRect)) {
             mLastClipRect.set(clipRect);
             try {
@@ -1285,10 +1286,10 @@
 
         // Adjust for surface insets.
         final LayoutParams attrs = w.getAttrs();
-        width += attrs.shadowInsets.left + attrs.shadowInsets.right;
-        height += attrs.shadowInsets.top + attrs.shadowInsets.bottom;
-        left -= attrs.shadowInsets.left;
-        top -= attrs.shadowInsets.top;
+        width += attrs.surfaceInsets.left + attrs.surfaceInsets.right;
+        height += attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
+        left -= attrs.surfaceInsets.left;
+        top -= attrs.surfaceInsets.top;
 
         final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
         if (surfaceMoved) {
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
new file mode 100644
index 0000000..ba7e253
--- /dev/null
+++ b/telecomm/java/android/telecomm/Call.java
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.DisconnectCause;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents an ongoing phone call that the in-call app should present to the user.
+ */
+public final class Call {
+    /**
+     * The state of a {@code Call} when newly created.
+     */
+    public static final int STATE_NEW = 0;
+
+    /**
+     * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
+     */
+    public static final int STATE_DIALING = 1;
+
+    /**
+     * The state of an incoming {@code Call} when ringing locally, but not yet connected.
+     */
+    public static final int STATE_RINGING = 2;
+
+    /**
+     * The state of a {@code Call} when in a holding state.
+     */
+    public static final int STATE_HOLDING = 3;
+
+    /**
+     * The state of a {@code Call} when actively supporting conversation.
+     */
+    public static final int STATE_ACTIVE = 4;
+
+    /**
+     * The state of a {@code Call} when no further voice or other communication is being
+     * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
+     * is no longer active, and the local data transport has or inevitably will release resources
+     * associated with this {@code Call}.
+     */
+    public static final int STATE_DISCONNECTED = 7;
+
+    public static class Details {
+        private final Uri mHandle;
+        private final int mHandlePresentation;
+        private final String mCallerDisplayName;
+        private final int mCallerDisplayNamePresentation;
+        private final PhoneAccount mAccount;
+        private final int mCapabilities;
+        private final int mDisconnectCauseCode;
+        private final String mDisconnectCauseMsg;
+        private final long mConnectTimeMillis;
+        private final GatewayInfo mGatewayInfo;
+
+        /**
+         * @return The handle (e.g., phone number) to which the {@code Call} is currently
+         * connected.
+         */
+        public Uri getHandle() {
+            return mHandle;
+        }
+
+        /**
+         * @return The presentation requirements for the handle. See
+         * {@link android.telecomm.CallPropertyPresentation} for valid values.
+         */
+        public int getHandlePresentation() {
+            return mHandlePresentation;
+        }
+
+        /**
+         * @return The display name for the caller.
+         */
+        public String getCallerDisplayName() {
+            return mCallerDisplayName;
+        }
+
+        /**
+         * @return The presentation requirements for the caller display name. See
+         * {@link android.telecomm.CallPropertyPresentation} for valid values.
+         */
+        public int getCallerDisplayNamePresentation() {
+            return mCallerDisplayNamePresentation;
+        }
+
+        /**
+         * @return The {@code PhoneAccount} whereby the {@code Call} is currently being routed.
+         */
+        public PhoneAccount getAccount() {
+            return mAccount;
+        }
+
+        /**
+         * @return A bitmask of the capabilities of the {@code Call}, as defined in
+         *         {@link CallCapabilities}.
+         */
+        public int getCapabilities() {
+            return mCapabilities;
+        }
+
+        /**
+         * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
+         * as a code chosen from among those declared in {@link DisconnectCause}.
+         */
+        public int getDisconnectCauseCode() {
+            return mDisconnectCauseCode;
+        }
+
+        /**
+         * @return For a {@link #STATE_DISCONNECTED} {@code Call}, an optional reason for
+         * disconnection expressed as a free text message.
+         */
+        public String getDisconnectCauseMsg() {
+            return mDisconnectCauseMsg;
+        }
+
+        /**
+         * @return The time the {@code Call} has been connected. This information is updated
+         * periodically, but user interfaces should not rely on this to display any "call time
+         * clock".
+         */
+        public long getConnectTimeMillis() {
+            return mConnectTimeMillis;
+        }
+
+        /**
+         * @return Information about any calling gateway the {@code Call} may be using.
+         */
+        public GatewayInfo getGatewayInfo() {
+            return mGatewayInfo;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o instanceof Details) {
+                Details d = (Details) o;
+                return
+                        Objects.equals(mHandle, d.mHandle) &&
+                        Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
+                        Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
+                        Objects.equals(mCallerDisplayNamePresentation,
+                                d.mCallerDisplayNamePresentation) &&
+                        Objects.equals(mAccount, d.mAccount) &&
+                        Objects.equals(mCapabilities, d.mCapabilities) &&
+                        Objects.equals(mDisconnectCauseCode, d.mDisconnectCauseCode) &&
+                        Objects.equals(mDisconnectCauseMsg, d.mDisconnectCauseMsg) &&
+                        Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
+                        Objects.equals(mGatewayInfo, d.mGatewayInfo);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return
+                    Objects.hashCode(mHandle) +
+                    Objects.hashCode(mHandlePresentation) +
+                    Objects.hashCode(mCallerDisplayName) +
+                    Objects.hashCode(mCallerDisplayNamePresentation) +
+                    Objects.hashCode(mAccount) +
+                    Objects.hashCode(mCapabilities) +
+                    Objects.hashCode(mDisconnectCauseCode) +
+                    Objects.hashCode(mDisconnectCauseMsg) +
+                    Objects.hashCode(mConnectTimeMillis) +
+                    Objects.hashCode(mGatewayInfo);
+        }
+
+        /** {@hide} */
+        public Details(
+                Uri handle,
+                int handlePresentation,
+                String callerDisplayName,
+                int callerDisplayNamePresentation,
+                PhoneAccount account,
+                int capabilities,
+                int disconnectCauseCode,
+                String disconnectCauseMsg,
+                long connectTimeMillis,
+                GatewayInfo gatewayInfo) {
+            mHandle = handle;
+            mHandlePresentation = handlePresentation;
+            mCallerDisplayName = callerDisplayName;
+            mCallerDisplayNamePresentation = callerDisplayNamePresentation;
+            mAccount = account;
+            mCapabilities = capabilities;
+            mDisconnectCauseCode = disconnectCauseCode;
+            mDisconnectCauseMsg = disconnectCauseMsg;
+            mConnectTimeMillis = connectTimeMillis;
+            mGatewayInfo = gatewayInfo;
+        }
+    }
+
+    public static abstract class Listener {
+        /**
+         * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
+         *
+         * TODO(ihab): Provide previous state also?
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param state The new state of the {@code Call}.
+         */
+        public void onStateChanged(Call call, int state) {}
+
+        /**
+         * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param parent The new parent of the {@code Call}.
+         */
+        public void onParentChanged(Call call, Call parent) {}
+
+        /**
+         * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param children The new children of the {@code Call}.
+         */
+        public void onChildrenChanged(Call call, List<Call> children) {}
+
+        /**
+         * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param details A {@code Details} object describing the {@code Call}.
+         */
+        public void onDetailsChanged(Call call, Details details) {}
+
+        /**
+         * Invoked when the text messages that can be used as responses to the incoming
+         * {@code Call} are loaded from the relevant database.
+         * See {@link #getCannedTextResponses()}.
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param cannedTextResponses The text messages useable as responses.
+         */
+        public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
+
+        /**
+         * Invoked when the outgoing {@code Call} has finished dialing but is sending DTMF signals
+         * that were embedded into the outgoing number.
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param remainingPostDialSequence The post-dial characters that remain to be sent.
+         */
+        public void onPostDial(Call call, String remainingPostDialSequence) {}
+
+        /**
+         * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
+         * character. This causes the post-dial signals to stop pending user confirmation. An
+         * implementation should present this choice to the user and invoke
+         * {@link #postDialContinue(boolean)} when the user makes the choice.
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param remainingPostDialSequence The post-dial characters that remain to be sent.
+         */
+        public void onPostDialWait(Call call, String remainingPostDialSequence) {}
+
+        /**
+         * Invoked when the {@code RemoteCallVideoProvider} of the {@code Call} has changed.
+         *
+         * @param call The {@code Call} invoking this method.
+         * @param callVideoProvider The {@code RemoteCallVideoProvider} associated with the
+         * {@code Call}.
+         */
+
+        public void onCallVideoProviderChanged(Call call,
+                RemoteCallVideoProvider callVideoProvider) {}
+
+        /**
+         * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
+         * up their UI for the {@code Call} in response to state transitions. Specifically,
+         * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
+         * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
+         * clients should wait for this method to be invoked.
+         *
+         * @param call The {@code Call} being destroyed.
+         */
+        public void onCallDestroyed(Call call) {}
+    }
+
+    private final Phone mPhone;
+    private final String mTelecommCallId;
+    private final InCallAdapter mInCallAdapter;
+    private Call mParent = null;
+    private int mState;
+    private final List<Call> mChildren = new ArrayList<>();
+    private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
+    private List<String> mCannedTextResponses = null;
+    private String mRemainingPostDialSequence;
+    private RemoteCallVideoProvider mCallVideoProvider;
+    private Details mDetails;
+    private final List<Listener> mListeners = new ArrayList<>();
+
+    /**
+     * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
+     *
+     * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
+     * remaining or this {@code Call} is not in a post-dial state.
+     */
+    public String getRemainingPostDialSequence() {
+        return mRemainingPostDialSequence;
+    }
+
+    /**
+     * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
+     */
+    public void answer() {
+        mInCallAdapter.answerCall(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
+     *
+     * @param rejectWithMessage Whether to reject with a text message.
+     * @param textMessage An optional text message with which to respond.
+     */
+    public void reject(boolean rejectWithMessage, String textMessage) {
+        mInCallAdapter.rejectCall(mTelecommCallId, rejectWithMessage, textMessage);
+    }
+
+    /**
+     * Instructs this {@code Call} to disconnect.
+     */
+    public void disconnect() {
+        mInCallAdapter.disconnectCall(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@code Call} to go on hold.
+     */
+    public void hold() {
+        mInCallAdapter.holdCall(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@link #STATE_HOLDING} call to release from hold.
+     */
+    public void unhold() {
+        mInCallAdapter.unholdCall(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
+     *
+     * Any other currently playing DTMF tone in the specified call is immediately stopped.
+     *
+     * @param digit A character representing the DTMF digit for which to play the tone. This
+     *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
+     */
+    public void playDtmfTone(char digit) {
+        mInCallAdapter.playDtmfTone(mTelecommCallId, digit);
+    }
+
+    /**
+     * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
+     * currently playing.
+     *
+     * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
+     * currently playing, this method will do nothing.
+     */
+    public void stopDtmfTone() {
+        mInCallAdapter.stopDtmfTone(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@code Call} to continue playing a post-dial DTMF string.
+     *
+     * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
+     * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
+     * While these tones are playing, this {@code Call} will notify listeners via
+     * {@link Listener#onPostDial(Call, String)}.
+     *
+     * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_PAUSE} symbol, this
+     * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
+     *
+     * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_WAIT} symbol, this
+     * {@code Call} will pause playing the tones and notify listeners via
+     * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app
+     * should display to the user an indication of this state and an affordance to continue
+     * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
+     * app should invoke the {@link #postDialContinue(boolean)} method.
+     *
+     * @param proceed Whether or not to continue with the post-dial sequence.
+     */
+    public void postDialContinue(boolean proceed) {
+        mInCallAdapter.postDialContinue(mTelecommCallId, proceed);
+    }
+
+    /**
+     * Notifies this {@code Call} that the phone account user interface element was touched.
+     *
+     * TODO(ihab): Figure out if and how we can generalize this
+     */
+    public void phoneAccountClicked() {
+        mInCallAdapter.phoneAccountClicked(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@code Call} to enter a conference.
+     */
+    public void conference() {
+        mInCallAdapter.conference(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@code Call} to split from any conference call with which it may be
+     * connected.
+     */
+    public void splitFromConference() {
+        mInCallAdapter.splitFromConference(mTelecommCallId);
+    }
+
+    /**
+     * Instructs this {@code Call} to swap itself with an existing background call, if one
+     * such call exists.
+     */
+    public void swapWithBackgroundCall() {
+        mInCallAdapter.swapWithBackgroundCall(mTelecommCallId);
+    }
+
+    /**
+     * Obtains the parent of this {@code Call} in a conference, if any.
+     *
+     * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
+     * child of any conference {@code Call}s.
+     */
+    public Call getParent() {
+        return mParent;
+    }
+
+    /**
+     * Obtains the children of this conference {@code Call}, if any.
+     *
+     * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
+     * {@code List} otherwise.
+     */
+    public List<Call> getChildren() {
+        return mUnmodifiableChildren;
+    }
+
+    /**
+     * Obtains the state of this {@code Call}.
+     *
+     * @return A state value, chosen from the {@code STATE_*} constants.
+     */
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Obtains a list of canned, pre-configured message responses to present to the user as
+     * ways of rejecting this {@code Call} using via a text message.
+     *
+     * @see #reject(boolean, String)
+     *
+     * @return A list of canned text message responses.
+     */
+    public List<String> getCannedTextResponses() {
+        return mCannedTextResponses;
+    }
+
+    /**
+     * Obtains an object that can be used to display video from this {@code Call}.
+     *
+     * @return An {@code ICallVideoProvider}.
+     */
+    public RemoteCallVideoProvider getCallVideoProvider() {
+        return mCallVideoProvider;
+    }
+
+    /**
+     * Obtains an object containing call details.
+     *
+     * @return A {@link Details} object. Depending on the state of the {@code Call}, the
+     * result may be {@code null}.
+     */
+    public Details getDetails() {
+        return mDetails;
+    }
+
+    /**
+     * Adds a listener to this {@code Call}.
+     *
+     * @param listener A {@code Listener}.
+     */
+    public void addListener(Listener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Removes a listener from this {@code Call}.
+     *
+     * @param listener A {@code Listener}.
+     */
+    public void removeListener(Listener listener) {
+        mListeners.remove(listener);
+    }
+
+    /** {@hide} */
+    Call(Phone phone, String telecommCallId, InCallAdapter inCallAdapter) {
+        mPhone = phone;
+        mTelecommCallId = telecommCallId;
+        mInCallAdapter = inCallAdapter;
+        mState = STATE_NEW;
+    }
+
+    /** {@hide} */
+    final String internalGetCallId() {
+        return mTelecommCallId;
+    }
+
+    /** {@hide} */
+    final void internalUpdate(InCallCall inCallCall) {
+        // First, we update the internal state as far as possible before firing any updates.
+
+        Details details = new Details(
+                inCallCall.getHandle(),
+                inCallCall.getHandlePresentation(),
+                inCallCall.getCallerDisplayName(),
+                inCallCall.getCallerDisplayNamePresentation(),
+                inCallCall.getAccount(),
+                inCallCall.getCapabilities(),
+                inCallCall.getDisconnectCauseCode(),
+                inCallCall.getDisconnectCauseMsg(),
+                inCallCall.getConnectTimeMillis(),
+                inCallCall.getGatewayInfo());
+        boolean detailsChanged = !Objects.equals(mDetails, details);
+        if (detailsChanged) {
+            mDetails = details;
+        }
+
+        boolean cannedTextResponsesChanged = false;
+        if (mCannedTextResponses == null && inCallCall.getCannedSmsResponses() != null
+                && !inCallCall.getCannedSmsResponses().isEmpty()) {
+            mCannedTextResponses = Collections.unmodifiableList(inCallCall.getCannedSmsResponses());
+        }
+
+        boolean callVideoProviderChanged = false;
+        try {
+            callVideoProviderChanged =
+                    !Objects.equals(mCallVideoProvider, inCallCall.getCallVideoProvider());
+            if (callVideoProviderChanged) {
+                mCallVideoProvider = inCallCall.getCallVideoProvider();
+            }
+        } catch (RemoteException e) {
+        }
+
+        int state = stateFromInCallCallState(inCallCall.getState());
+        boolean stateChanged = mState != state;
+        if (stateChanged) {
+            mState = state;
+        }
+
+        if (inCallCall.getParentCallId() != null) {
+            mParent = mPhone.internalGetCallByTelecommId(inCallCall.getParentCallId());
+        }
+
+        mChildren.clear();
+        if (inCallCall.getChildCallIds() != null) {
+            for (int i = 0; i < inCallCall.getChildCallIds().size(); i++) {
+                mChildren.add(mPhone.internalGetCallByTelecommId(
+                        inCallCall.getChildCallIds().get(i)));
+            }
+        }
+
+        // Now we fire updates, ensuring that any client who listens to any of these notifications
+        // gets the most up-to-date state.
+
+        if (stateChanged) {
+            fireStateChanged(mState);
+        }
+        if (detailsChanged) {
+            fireDetailsChanged(mDetails);
+        }
+        if (cannedTextResponsesChanged) {
+            fireCannedTextResponsesLoaded(mCannedTextResponses);
+        }
+        if (callVideoProviderChanged) {
+            fireCallVideoProviderChanged(mCallVideoProvider);
+        }
+
+        // If we have transitioned to DISCONNECTED, that means we need to notify clients and
+        // remove ourselves from the Phone. Note that we do this after completing all state updates
+        // so a client can cleanly transition all their UI to the state appropriate for a
+        // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
+        if (mState == STATE_DISCONNECTED) {
+            fireCallDestroyed();
+            mPhone.internalRemoveCall(this);
+        }
+    }
+
+    /** {@hide} */
+    final void internalSetPostDial(String remaining) {
+        mRemainingPostDialSequence = remaining;
+        firePostDial(mRemainingPostDialSequence);
+    }
+
+    /** {@hide} */
+    final void internalSetPostDialWait(String remaining) {
+        mRemainingPostDialSequence = remaining;
+        firePostDialWait(mRemainingPostDialSequence);
+    }
+
+    private void fireStateChanged(int newState) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onStateChanged(this, newState);
+        }
+    }
+
+    private void fireParentChanged(Call newParent) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onParentChanged(this, newParent);
+        }
+    }
+
+    private void fireChildrenChanged(List<Call> children) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onChildrenChanged(this, children);
+        }
+    }
+
+    private void fireDetailsChanged(Details details) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onDetailsChanged(this, details);
+        }
+    }
+
+    private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onCannedTextResponsesLoaded(this, cannedTextResponses);
+        }
+    }
+
+    private void fireCallVideoProviderChanged(RemoteCallVideoProvider callVideoProvider) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onCallVideoProviderChanged(this, callVideoProvider);
+        }
+    }
+
+    private void firePostDial(String remainingPostDialSequence) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onPostDial(this, remainingPostDialSequence);
+        }
+    }
+
+    private void firePostDialWait(String remainingPostDialSequence) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onPostDialWait(this, remainingPostDialSequence);
+        }
+    }
+
+    private void fireCallDestroyed() {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onCallDestroyed(this);
+        }
+    }
+
+    private int stateFromInCallCallState(CallState inCallCallState) {
+        switch (inCallCallState) {
+            case NEW:
+                return STATE_NEW;
+            case DIALING:
+                return STATE_DIALING;
+            case RINGING:
+                return STATE_RINGING;
+            case ACTIVE:
+                return STATE_ACTIVE;
+            case ON_HOLD:
+                return STATE_HOLDING;
+            case DISCONNECTED:
+                return STATE_DISCONNECTED;
+            case ABORTED:
+                return STATE_DISCONNECTED;
+            default:
+                Log.wtf(this, "Unrecognized CallState %s", inCallCallState);
+                return STATE_NEW;
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.java b/telecomm/java/android/telecomm/CallServiceDescriptor.java
deleted file mode 100644
index 5ae07d3..0000000
--- a/telecomm/java/android/telecomm/CallServiceDescriptor.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telecomm;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.util.Locale;
-import java.util.UUID;
-
-/**
- * An immutable object containing information about a given {@link ConnectionService}. Instances are
- * created using the enclosed {@link Builder}.
- */
-public final class CallServiceDescriptor implements Parcelable {
-    private static final String TAG = CallServiceDescriptor.class.getSimpleName();
-
-    /**
-     * A placeholder value indicating an invalid network type.
-     * @hide
-     */
-    private static final int FLAG_INVALID = 0;
-
-    /**
-     * Indicates that the device must be connected to a Wi-Fi network in order for the backing
-     * {@link ConnectionService} to be used.
-     */
-    public static final int FLAG_WIFI = 0x01;
-
-    /**
-     * Indicates that the device must be connected to a cellular PSTN network in order for the
-     * backing {@link ConnectionService} to be used.
-     */
-    public static final int FLAG_PSTN = 0x02;
-
-    /**
-     * Indicates that the device must be connected to a cellular data network in order for the
-     * backing {@link ConnectionService} to be used.
-     */
-    public static final int FLAG_MOBILE = 0x04;
-
-    /**
-     * Represents all of the defined FLAG_ constants so validity can be easily checked.
-     * @hide
-     */
-    public static final int FLAG_ALL = FLAG_WIFI | FLAG_PSTN | FLAG_MOBILE;
-
-    /**
-     * A unique ID used to identify a given instance.
-     */
-    private final String mConnectionServiceId;
-
-    /**
-     * The {@link ComponentName} of the {@link ConnectionService} implementation which this is
-     * describing.
-     */
-    private final ComponentName mComponentName;
-
-    /**
-     * The type of connection that the {@link ConnectionService} requires; will be one of the FLAG_*
-     * constants defined in this class.
-     */
-    private final int mNetworkType;
-
-    private CallServiceDescriptor(
-            String connectionServiceId,
-            ComponentName componentName,
-            int networkType) {
-
-        mConnectionServiceId = connectionServiceId;
-        mComponentName = componentName;
-        mNetworkType = networkType;
-    }
-
-    /**
-     * @return The ID used to identify this {@link ConnectionService}.
-     */
-    public String getConnectionServiceId() {
-        return mConnectionServiceId;
-    }
-
-    /**
-     * @return The {@link ComponentName} of the {@link ConnectionService}.
-     */
-    public ComponentName getServiceComponent() {
-        return mComponentName;
-    }
-
-    /**
-     * @return The network type required by the {@link ConnectionService} to place a call.
-     */
-    public int getNetworkType() {
-        return mNetworkType;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof CallServiceDescriptor)) {
-            return false;
-        }
-        CallServiceDescriptor descriptor = (CallServiceDescriptor) obj;
-        return mConnectionServiceId.equals(descriptor.mConnectionServiceId) &&
-                mComponentName.equals(descriptor.mComponentName) &&
-                mNetworkType == descriptor.mNetworkType;
-    }
-
-    @Override
-    public String toString() {
-        return String.format(Locale.US, "[%s, component: %s]",
-                CallServiceDescriptor.class.getSimpleName(),
-                mComponentName == null ? "null" : mComponentName.flattenToShortString());
-    }
-
-    /**
-     * @param context {@link Context} to use for the construction of the {@link Builder}.
-     * @return A new {@link Builder} instance.
-     */
-    public static Builder newBuilder(Context context) {
-        return new Builder(context);
-    }
-
-    /**
-     * Creates {@link CallServiceDescriptor} instances. Builders should be created with the
-     * {@link CallServiceDescriptor#newBuilder(Context)} method.
-     */
-    public static class Builder {
-        /** The {@link Context} to use to verify {@link ComponentName} ownership. */
-        private Context mContext;
-
-        /** The {@link ComponentName} pointing to the backing {@link ConnectionService}. */
-        private ComponentName mComponentName;
-
-        /** The required network type that the {@link ConnectionService} needs. */
-        private int mNetworkType = FLAG_INVALID;
-
-        private Builder(Context context) {
-            mContext = context;
-        }
-
-        /**
-         * Set which {@link ConnectionService} this {@link CallServiceDescriptor} is describing.
-         *
-         * @param serviceClass The {@link ConnectionService} class
-         * @return This {@link Builder} for method chaining.
-         */
-        public Builder setConnectionService(Class<? extends ConnectionService> serviceClass) {
-            mComponentName = new ComponentName(mContext, serviceClass);
-            return this;
-        }
-
-        /**
-         * Which network type the backing {@link ConnectionService} requires. This must be one of
-         * the {@link CallServiceDescriptor}.TYPE_* fields.
-         *
-         * @param networkType Which network type the backing {@link ConnectionService} requires.
-         * @return This {@link Builder} for method chaining.
-         */
-        public Builder setNetworkType(int networkType) {
-            mNetworkType = networkType;
-            return this;
-        }
-
-        /**
-         * @return A constructed {@link CallServiceDescriptor} object.
-         */
-        public CallServiceDescriptor build() {
-            // STOPSHIP: Verify validity of ComponentName (permissions, intents, etc)
-
-            // Make sure that they passed in a valid network flag combination
-            if (mNetworkType == FLAG_INVALID || ((mNetworkType & FLAG_ALL) == 0)) {
-
-                Log.wtf(TAG, "Invalid network type for " + mComponentName);
-                // Revert them back to TYPE_INVALID so it won't be considered.
-                mNetworkType = FLAG_INVALID;
-            }
-
-            // TODO: Should we use a sha1 of the ComponentName? Would prevent duplicates.
-            return new CallServiceDescriptor(
-                UUID.randomUUID().toString(), mComponentName, mNetworkType);
-        }
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mConnectionServiceId);
-        dest.writeParcelable(mComponentName, 0);
-        dest.writeInt(mNetworkType);
-    }
-
-    public static final Creator<CallServiceDescriptor> CREATOR =
-            new Creator<CallServiceDescriptor>() {
-        @Override
-        public CallServiceDescriptor createFromParcel(Parcel source) {
-            String id = source.readString();
-            ComponentName componentName = source.readParcelable(
-                    CallServiceDescriptor.class.getClassLoader());
-            int networkType = source.readInt();
-
-            return new CallServiceDescriptor(id, componentName, networkType);
-        }
-
-        @Override
-        public CallServiceDescriptor[] newArray(int size) {
-            return new CallServiceDescriptor[size];
-        }
-    };
-}
diff --git a/telecomm/java/android/telecomm/CallServiceLookupResponse.java b/telecomm/java/android/telecomm/CallServiceLookupResponse.java
deleted file mode 100644
index dd35a24..0000000
--- a/telecomm/java/android/telecomm/CallServiceLookupResponse.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telecomm;
-
-import android.os.RemoteException;
-
-import com.android.internal.telecomm.ICallServiceLookupResponse;
-
-import java.util.List;
-
-/**
- * Used by {@link CallServiceProvider} to return a list of {@link CallServiceDescriptor}s.
- */
-public final class CallServiceLookupResponse {
-    private final ICallServiceLookupResponse mResponse;
-
-    /**
-     * {@hide}
-     */
-    public CallServiceLookupResponse(ICallServiceLookupResponse response) {
-        mResponse = response;
-    }
-
-    /**
-     * Passes the sorted list of preferred {@link CallServiceDescriptor}s back to Telecomm.  Used
-     * in the context of attempting to place a pending outgoing call.
-     *
-     * @param callServiceDescriptors The set of call-service descriptors from
-     * {@link CallServiceProvider}.
-     */
-    public void setCallServiceDescriptors(List<CallServiceDescriptor> callServiceDescriptors) {
-        try {
-            mResponse.setCallServiceDescriptors(callServiceDescriptors);
-        } catch (RemoteException e) {
-        }
-    }
-}
diff --git a/telecomm/java/android/telecomm/CallServiceProvider.java b/telecomm/java/android/telecomm/CallServiceProvider.java
deleted file mode 100644
index c50334a..0000000
--- a/telecomm/java/android/telecomm/CallServiceProvider.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telecomm;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-
-import com.android.internal.telecomm.ICallServiceLookupResponse;
-import com.android.internal.telecomm.ICallServiceProvider;
-
-/**
- * Base implementation of a call service provider which extends {@link Service}. This class
- * should be extended by an app that wants to supply phone calls to be handled and managed by
- * the device's in-call interface. All method-calls from the framework to the call service provider
- * are passed through to the main thread for before executing the overriden methods of
- * CallServiceProvider.
- *
- * TODO(santoscordon): Improve paragraph above once the final design is in place. Needs more
- * about how this can be used.
- */
-public abstract class CallServiceProvider extends Service {
-
-    /**
-     * Default Handler used to consolidate binder method calls onto a single thread.
-     */
-    private final class CallServiceProviderMessageHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_LOOKUP_CALL_SERVICES:
-                    CallServiceLookupResponse response =
-                            new CallServiceLookupResponse((ICallServiceLookupResponse) msg.obj);
-                    lookupCallServices(response);
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Default ICallServiceProvider implementation provided to CallsManager via {@link #onBind}.
-     */
-    private final class CallServiceProviderWrapper extends ICallServiceProvider.Stub {
-        /** {@inheritDoc} */
-        @Override
-        public void lookupCallServices(ICallServiceLookupResponse callServiceLookupResponse) {
-            Message message = mMessageHandler.obtainMessage(
-                    MSG_LOOKUP_CALL_SERVICES, callServiceLookupResponse);
-            message.sendToTarget();
-        }
-    }
-
-    // Only used internally by this class.
-    // Binder method calls on this service can occur on multiple threads. These messages are used
-    // in conjunction with {@link #mMessageHandler} to ensure that all callbacks are handled on a
-    // single thread.  Keeping it on a single thread allows CallService implementations to avoid
-    // needing multi-threaded code in their own callback routines.
-    private static final int MSG_LOOKUP_CALL_SERVICES = 1;
-
-    /**
-     * Message handler for consolidating binder callbacks onto a single thread.
-     * See {@link CallServiceProviderMessageHandler}.
-     */
-    private final CallServiceProviderMessageHandler mMessageHandler;
-
-    /**
-     * Default binder implementation of {@link ICallServiceProvider} interface.
-     */
-    private final CallServiceProviderWrapper mBinder;
-
-    /**
-     * Protected constructor called only by subclasses creates the binder interface and
-     * single-threaded message handler.
-     */
-    protected CallServiceProvider() {
-        mMessageHandler = new CallServiceProviderMessageHandler();
-        mBinder = new CallServiceProviderWrapper();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    /**
-     * Initiates the process to retrieve the list of {@link CallServiceDescriptor}s implemented by
-     * this provider.
-     *
-     * @param response The response object through which the list of call services is sent.
-     */
-    public abstract void lookupCallServices(CallServiceLookupResponse response);
-}
diff --git a/telecomm/java/android/telecomm/CallState.java b/telecomm/java/android/telecomm/CallState.java
index 152c202..a464da5 100644
--- a/telecomm/java/android/telecomm/CallState.java
+++ b/telecomm/java/android/telecomm/CallState.java
@@ -48,22 +48,6 @@
     RINGING,
 
     /**
-     * Indicates that the call is active but in a "post-dial" state where Telecomm is now sending
-     * some dual-tone multi-frequency signaling (DTMF) tones appended to the dialed number. Normal
-     * transitions are to {@link #POST_DIAL_WAIT} when the post-dial string requires user
-     * confirmation to proceed, {@link #ACTIVE} when the post-dial tones are completed, or
-     * {@link #DISCONNECTED}.
-     */
-    POST_DIAL,
-
-    /**
-     * Indicates that the call was in the {@link #POST_DIAL} state but is now waiting for user
-     * confirmation before the remaining digits can be sent. Normal transitions are to
-     * {@link #POST_DIAL} when the user asks Telecomm to proceed with the post-dial sequence.
-     */
-    POST_DIAL_WAIT,
-
-    /**
      * Indicates that a call is currently connected to another party and a communication channel is
      * open between them. The normal transition to this state is by the user answering a
      * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
diff --git a/telecomm/java/android/telecomm/CallVideoClient.java b/telecomm/java/android/telecomm/CallVideoClient.java
index 76b28fa..fb970dc 100644
--- a/telecomm/java/android/telecomm/CallVideoClient.java
+++ b/telecomm/java/android/telecomm/CallVideoClient.java
@@ -241,6 +241,7 @@
      *
      * @param callCameraCapabilities The changed camera capabilities.
      */
-    public abstract void onHandleCameraCapabilitiesChange(CallCameraCapabilities callCameraCapabilities);
+    public abstract void onHandleCameraCapabilitiesChange(
+            CallCameraCapabilities callCameraCapabilities);
 }
 
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index d8293a5..66cf1df 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -24,7 +24,7 @@
  * Receives commands from {@link InCallService} implementations which should be executed by
  * Telecomm. When Telecomm binds to a {@link InCallService}, an instance of this class is given to
  * the in-call service through which it can manipulate live (active, dialing, ringing) calls. When
- * the in-call service is notified of new calls ({@link InCallService#addCall}), it can use the
+ * the in-call service is notified of new calls, it can use the
  * given call IDs to execute commands such as {@link #answerCall} for incoming calls or
  * {@link #disconnectCall} for active calls the user would like to end. Some commands are only
  * appropriate for calls in certain states; please consult each method for such limitations.
@@ -167,16 +167,15 @@
      * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
      * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
      * While these tones are playing, Telecomm will notify the {@link InCallService} that the call
-     * is in the {@link InCallService#setPostDial(String,String)} state.
+     * is in the post dial state.
      *
      * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_PAUSE} symbol, Telecomm
      * will temporarily pause playing the tones for a pre-defined period of time.
      *
      * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_WAIT} symbol, Telecomm
      * will pause playing the tones and notify the {@link InCallService} that the call is in the
-     * {@link InCallService#setPostDialWait(String,String)} state. When the user decides to continue
-     * the postdial sequence, the {@link InCallService} should invoke the
-     * {@link #postDialContinue(String,boolean)} method.
+     * post dial wait state. When the user decides to continue the postdial sequence, the
+     * {@link InCallService} should invoke the {@link #postDialContinue(String,boolean)} method.
      *
      * @param callId The unique ID of the call for which postdial string playing should continue.
      * @param proceed Whether or not to continue with the post-dial sequence.
diff --git a/telecomm/java/android/telecomm/InCallCall.java b/telecomm/java/android/telecomm/InCallCall.java
index 7c35020..355c260 100644
--- a/telecomm/java/android/telecomm/InCallCall.java
+++ b/telecomm/java/android/telecomm/InCallCall.java
@@ -45,7 +45,6 @@
     private final int mCallerDisplayNamePresentation;
     private final GatewayInfo mGatewayInfo;
     private final PhoneAccount mAccount;
-    private final CallServiceDescriptor mCurrentCallServiceDescriptor;
     private final ICallVideoProvider mCallVideoProvider;
     private RemoteCallVideoProvider mRemoteCallVideoProvider;
     private final String mParentCallId;
@@ -67,7 +66,6 @@
             int callerDisplayNamePresentation,
             GatewayInfo gatewayInfo,
             PhoneAccount account,
-            CallServiceDescriptor descriptor,
             ICallVideoProvider callVideoProvider,
             String parentCallId,
             List<String> childCallIds,
@@ -85,7 +83,6 @@
         mCallerDisplayNamePresentation = callerDisplayNamePresentation;
         mGatewayInfo = gatewayInfo;
         mAccount = account;
-        mCurrentCallServiceDescriptor = descriptor;
         mCallVideoProvider = callVideoProvider;
         mParentCallId = parentCallId;
         mChildCallIds = childCallIds;
@@ -165,11 +162,6 @@
         return mAccount;
     }
 
-    /** The descriptor for the call service currently routing this call. */
-    public CallServiceDescriptor getCurrentCallServiceDescriptor() {
-        return mCurrentCallServiceDescriptor;
-    }
-
     /**
      * Returns an object for remotely communicating through the call video provider's binder.
      * @return The call video provider.
@@ -232,7 +224,6 @@
             int callerDisplayNamePresentation = source.readInt();
             GatewayInfo gatewayInfo = source.readParcelable(classLoader);
             PhoneAccount account = source.readParcelable(classLoader);
-            CallServiceDescriptor descriptor = source.readParcelable(classLoader);
             ICallVideoProvider callVideoProvider =
                     ICallVideoProvider.Stub.asInterface(source.readStrongBinder());
             String parentCallId = source.readString();
@@ -242,8 +233,7 @@
             return new InCallCall(id, state, disconnectCauseCode, disconnectCauseMsg,
                     cannedSmsResponses, capabilities, connectTimeMillis, handle, handlePresentation,
                     callerDisplayName, callerDisplayNamePresentation, gatewayInfo,
-                    account, descriptor, callVideoProvider, parentCallId, childCallIds,
-                    statusHints);
+                    account, callVideoProvider, parentCallId, childCallIds, statusHints);
         }
 
         @Override
@@ -274,7 +264,6 @@
         destination.writeInt(mCallerDisplayNamePresentation);
         destination.writeParcelable(mGatewayInfo, 0);
         destination.writeParcelable(mAccount, 0);
-        destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
         destination.writeStrongBinder(
                 mCallVideoProvider != null ? mCallVideoProvider.asBinder() : null);
         destination.writeString(mParentCallId);
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
index 31291fb..028b6e4 100644
--- a/telecomm/java/android/telecomm/InCallService.java
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -16,8 +16,6 @@
 
 package android.telecomm;
 
-import android.app.Service;
-import android.content.Intent;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -31,11 +29,10 @@
  * This service is implemented by any app that wishes to provide the user-interface for managing
  * phone calls. Telecomm binds to this service while there exists a live (active or incoming)
  * call, and uses it to notify the in-call app of any live and and recently disconnected calls.
- * TODO(santoscordon): Needs more/better description of lifecycle once the interface is better
- * defined.
+ *
  * TODO(santoscordon): What happens if two or more apps on a given device implement this interface?
  */
-public abstract class InCallService extends Service {
+public abstract class InCallService {
     private static final int MSG_SET_IN_CALL_ADAPTER = 1;
     private static final int MSG_ADD_CALL = 2;
     private static final int MSG_UPDATE_CALL = 3;
@@ -50,21 +47,21 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_SET_IN_CALL_ADAPTER:
-                    mAdapter = new InCallAdapter((IInCallAdapter) msg.obj);
-                    onAdapterAttached(mAdapter);
+                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
+                    onPhoneCreated(mPhone);
                     break;
                 case MSG_ADD_CALL:
-                    addCall((InCallCall) msg.obj);
+                    mPhone.internalAddCall((InCallCall) msg.obj);
                     break;
                 case MSG_UPDATE_CALL:
-                    updateCall((InCallCall) msg.obj);
+                    mPhone.internalUpdateCall((InCallCall) msg.obj);
                     break;
-                case MSG_SET_POST_DIAL: {
+                                case MSG_SET_POST_DIAL: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         String callId = (String) args.arg1;
                         String remaining = (String) args.arg2;
-                        setPostDial(callId, remaining);
+                        mPhone.internalSetPostDial(callId, remaining);
                     } finally {
                         args.recycle();
                     }
@@ -75,17 +72,17 @@
                     try {
                         String callId = (String) args.arg1;
                         String remaining = (String) args.arg2;
-                        setPostDialWait(callId, remaining);
+                        mPhone.internalSetPostDialWait(callId, remaining);
                     } finally {
                         args.recycle();
                     }
                     break;
                 }
                 case MSG_ON_AUDIO_STATE_CHANGED:
-                    onAudioStateChanged((CallAudioState) msg.obj);
+                    mPhone.internalAudioStateChanged((CallAudioState) msg.obj);
                     break;
                 case MSG_BRING_TO_FOREGROUND:
-                    bringToForeground(msg.arg1 == 1);
+                    mPhone.internalBringToForeground(msg.arg1 == 1);
                     break;
                 default:
                     break;
@@ -142,85 +139,41 @@
         }
     }
 
-    private final InCallServiceBinder mBinder;
+    private Phone mPhone;
 
-    private InCallAdapter mAdapter;
+    protected InCallService() {}
 
-    protected InCallService() {
-        mBinder = new InCallServiceBinder();
-    }
-
-    @Override
-    public final IBinder onBind(Intent intent) {
-        return mBinder;
+    public final IBinder getBinder() {
+        return new InCallServiceBinder();
     }
 
     /**
-     * @return The attached {@link InCallAdapter} if attached, or null otherwise.
+     * Obtain the {@code Phone} associated with this {@code InCallService}.
+     *
+     * @return The {@code Phone} object associated with this {@code InCallService}, or {@code null}
+     * if the {@code InCallService} is not in a state where it has an associated {@code Phone}.
      */
-    protected final InCallAdapter getAdapter() {
-        return mAdapter;
+    public Phone getPhone() {
+        return mPhone;
     }
 
     /**
-     * Lifecycle callback which is called when this {@link InCallService} has been attached
-     * to a {@link InCallAdapter}, indicating {@link #getAdapter()} is now safe to use.
+     * Invoked when the {@code Phone} has been created. This is a signal to the in-call experience
+     * to start displaying in-call information to the user. Each instance of {@code InCallService}
+     * will have only one {@code Phone}, and this method will be called exactly once in the
+     * lifetime of the {@code InCallService}.
      *
-     * @param adapter The adapter now attached to this in-call service.
+     * @param phone The {@code Phone} object associated with this {@code InCallService}.
      */
-    protected void onAdapterAttached(InCallAdapter adapter) {
-    }
+    public void onPhoneCreated(Phone phone) { }
 
     /**
-     * Indicates to the in-call app that a new call has been created and an appropriate
-     * user-interface should be built and shown to notify the user.
+     * Invoked when a {@code Phone} has been destroyed. This is a signal to the in-call experience
+     * to stop displaying in-call information to the user. This method will be called exactly once
+     * in the lifetime of the {@code InCallService}, and it will always be called after a previous
+     * call to {@link #onPhoneCreated(Phone)}.
      *
-     * @param call Information about the new call.
+     * @param phone The {@code Phone} object associated with this {@code InCallService}.
      */
-     protected abstract void addCall(InCallCall call);
-
-    /**
-     * Call when information about a call has changed.
-     *
-     * @param call Information about the new call.
-     */
-     protected abstract void updateCall(InCallCall call);
-
-    /**
-     * Indicates to the in-call app that the specified call is active but in a "post-dial" state
-     * where Telecomm is now sending some dual-tone multi-frequency signaling (DTMF) tones appended
-     * to the dialed number. Normal transitions are to {@link #setPostDialWait(String,String)} when
-     * the post-dial string requires user confirmation to proceed, and {@link CallState#ACTIVE} when
-     * the post-dial tones are completed.
-     *
-     * @param callId The identifier of the call changing state.
-     * @param remaining The remaining postdial string to be dialed.
-     */
-    protected abstract void setPostDial(String callId, String remaining);
-
-    /**
-     * Indicates to the in-call app that the specified call was in the
-     * {@link #setPostDial(String,String)} state but is now waiting for user confirmation before the
-     * remaining digits can be sent. Normal transitions are to {@link #setPostDial(String,String)}
-     * when the user asks Telecomm to proceed with the post-dial sequence and the in-call app
-     * informs Telecomm of this by invoking {@link InCallAdapter#postDialContinue(String,boolean)}.
-     *
-     * @param callId The identifier of the call changing state.
-     * @param remaining The remaining postdial string to be dialed.
-     */
-    protected abstract void setPostDialWait(String callId, String remaining);
-
-    /**
-     * Called when the audio state changes.
-     *
-     * @param audioState The new {@link CallAudioState}.
-     */
-    protected abstract void onAudioStateChanged(CallAudioState audioState);
-
-    /**
-     * Brings the in-call screen to the foreground.
-     *
-     * @param showDialpad If true, put up the dialpad when the screen is shown.
-     */
-    protected abstract void bringToForeground(boolean showDialpad);
+    public void onPhoneDestroyed(Phone phone) { }
 }
diff --git a/telecomm/java/android/telecomm/Phone.java b/telecomm/java/android/telecomm/Phone.java
new file mode 100644
index 0000000..9c97b45
--- /dev/null
+++ b/telecomm/java/android/telecomm/Phone.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A unified virtual device providing a means of voice (and other) communication on a device.
+ */
+public final class Phone {
+
+    public abstract static class Listener {
+        /**
+         * Called when the audio state changes.
+         *
+         * @param phone The {@code Phone} calling this method.
+         * @param audioState The new {@link CallAudioState}.
+         */
+        public void onAudioStateChanged(Phone phone, CallAudioState audioState) { }
+
+        /**
+         * Called to bring the in-call screen to the foreground. The in-call experience should
+         * respond immediately by coming to the foreground to inform the user of the state of
+         * ongoing {@code Call}s.
+         *
+         * @param phone The {@code Phone} calling this method.
+         * @param showDialpad If true, put up the dialpad when the screen is shown.
+         */
+        public void onBringToForeground(Phone phone, boolean showDialpad) { }
+
+        /**
+         * Called when a {@code Call} has been added to this in-call session. The in-call user
+         * experience should add necessary state listeners to the specified {@code Call} and
+         * immediately start to show the user information about the existence
+         * and nature of this {@code Call}. Subsequent invocations of {@link #getCalls()} will
+         * include this {@code Call}.
+         *
+         * @param phone The {@code Phone} calling this method.
+         * @param call A newly added {@code Call}.
+         */
+        public void onCallAdded(Phone phone, Call call) { }
+
+        /**
+         * Called when a {@code Call} has been removed from this in-call session. The in-call user
+         * experience should remove any state listeners from the specified {@code Call} and
+         * immediately stop displaying any information about this {@code Call}.
+         * Subsequent invocations of {@link #getCalls()} will no longer include this {@code Call}.
+         *
+         * @param phone The {@code Phone} calling this method.
+         * @param call A newly removed {@code Call}.
+         */
+        public void onCallRemoved(Phone phone, Call call) { }
+    }
+
+    // A Map allows us to track each Call by its Telecomm-specified call ID
+    private final Map<String, Call> mCallByTelecommCallId = new ArrayMap<>();
+
+    // A List allows us to keep the Calls in a stable iteration order so that casually developed
+    // user interface components do not incur any spurious jank
+    private final List<Call> mCalls = new ArrayList<>();
+
+    // An unmodifiable view of the above List can be safely shared with subclass implementations
+    private final List<Call> mUnmodifiableCalls = Collections.unmodifiableList(mCalls);
+
+    private final InCallAdapter mInCallAdapter;
+
+    private CallAudioState mAudioState;
+
+    private final List<Listener> mListeners = new ArrayList<>();
+
+    /** {@hide} */
+    Phone(InCallAdapter adapter) {
+        mInCallAdapter = adapter;
+    }
+
+    /** {@hide} */
+    final void internalAddCall(InCallCall inCallCall) {
+        Call call = new Call(this, inCallCall.getId(), mInCallAdapter);
+        mCallByTelecommCallId.put(inCallCall.getId(), call);
+        mCalls.add(call);
+        checkCallTree(inCallCall);
+        call.internalUpdate(inCallCall);
+        fireCallAdded(call);
+     }
+
+    /** {@hide} */
+    final void internalRemoveCall(Call call) {
+        mCallByTelecommCallId.remove(call.internalGetCallId());
+        mCalls.remove(call);
+        fireCallRemoved(call);
+    }
+
+    /** {@hide} */
+    final void internalUpdateCall(InCallCall inCallCall) {
+         Call call = mCallByTelecommCallId.get(inCallCall.getId());
+         if (call != null) {
+             checkCallTree(inCallCall);
+             call.internalUpdate(inCallCall);
+         }
+     }
+
+    /** {@hide} */
+    final void internalSetPostDial(String callId, String remaining) {
+        Call call = mCallByTelecommCallId.get(callId);
+        if (call != null) {
+            call.internalSetPostDial(remaining);
+        }
+    }
+
+    /** {@hide} */
+    final void internalSetPostDialWait(String callId, String remaining) {
+        Call call = mCallByTelecommCallId.get(callId);
+        if (call != null) {
+            call.internalSetPostDialWait(remaining);
+        }
+    }
+
+    /** {@hide} */
+    final void internalAudioStateChanged(CallAudioState callAudioState) {
+        if (!Objects.equals(mAudioState, callAudioState)) {
+            mAudioState = callAudioState;
+            fireAudioStateChanged(callAudioState);
+        }
+    }
+
+    /** {@hide} */
+    final Call internalGetCallByTelecommId(String telecommId) {
+        return mCallByTelecommCallId.get(telecommId);
+    }
+
+    /** {@hide} */
+    final void internalBringToForeground(boolean showDialpad) {
+        fireBringToForeground(showDialpad);
+    }
+
+    /**
+     * Adds a listener to this {@code Phone}.
+     *
+     * @param listener A {@code Listener} object.
+     */
+    public final void addListener(Listener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Removes a listener from this {@code Phone}.
+     *
+     * @param listener A {@code Listener} object.
+     */
+    public final void removeListener(Listener listener) {
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Obtains the current list of {@code Call}s to be displayed by this in-call experience.
+     *
+     * @return A list of the relevant {@code Call}s.
+     */
+    public final List<Call> getCalls() {
+        return mUnmodifiableCalls;
+    }
+
+    /**
+     * Sets the microphone mute state. When this request is honored, there will be change to
+     * the {@link #getAudioState()}.
+     *
+     * @param state {@code true} if the microphone should be muted; {@code false} otherwise.
+     */
+    public final void setMuted(boolean state) {
+        mInCallAdapter.mute(state);
+    }
+
+    /**
+     * Sets the audio route (speaker, bluetooth, etc...).  When this request is honored, there will
+     * be change to the {@link #getAudioState()}.
+     *
+     * @param route The audio route to use.
+     */
+    public final void setAudioRoute(int route) {
+        mInCallAdapter.setAudioRoute(route);
+    }
+
+    /**
+     * Obtains the current phone call audio state of the {@code Phone}.
+     *
+     * @return An object encapsulating the audio state.
+     */
+    public final CallAudioState getAudioState() {
+        return mAudioState;
+    }
+
+    private void fireCallAdded(Call call) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onCallAdded(this, call);
+        }
+    }
+
+    private void fireCallRemoved(Call call) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onCallRemoved(this, call);
+        }
+    }
+
+    private void fireAudioStateChanged(CallAudioState audioState) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onAudioStateChanged(this, audioState);
+        }
+    }
+
+    private void fireBringToForeground(boolean showDialpad) {
+        Listener[] listeners = mListeners.toArray(new Listener[mListeners.size()]);
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].onBringToForeground(this, showDialpad);
+        }
+    }
+
+    private void checkCallTree(InCallCall inCallCall) {
+        if (inCallCall.getParentCallId() != null &&
+                !mCallByTelecommCallId.containsKey(inCallCall.getParentCallId())) {
+            Log.wtf(this, "InCallCall %s has nonexistent parent %s",
+                    inCallCall.getId(), inCallCall.getParentCallId());
+        }
+        if (inCallCall.getChildCallIds() != null) {
+            for (int i = 0; i < inCallCall.getChildCallIds().size(); i++) {
+                if (!mCallByTelecommCallId.containsKey(inCallCall.getChildCallIds().get(i))) {
+                    Log.wtf(this, "InCallCall %s has nonexistent child %s",
+                            inCallCall.getId(), inCallCall.getChildCallIds().get(i));
+                }
+            }
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/PhoneAccount.java b/telecomm/java/android/telecomm/PhoneAccount.java
index 4e440d8..c1eec83 100644
--- a/telecomm/java/android/telecomm/PhoneAccount.java
+++ b/telecomm/java/android/telecomm/PhoneAccount.java
@@ -17,52 +17,64 @@
 package android.telecomm;
 
 import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Rlog;
-import android.util.DisplayMetrics;
-import android.util.Log;
 
-import java.util.MissingResourceException;
 import java.util.Objects;
 
 /**
  * Represents a distinct account, line of service or call placement method that
  * the system can use to place phone calls.
  */
-public final class PhoneAccount implements Parcelable {
+public class PhoneAccount implements Parcelable {
 
-    private static final int NO_DENSITY = -1;
 
-    private static final String LOG_TAG = "Account";
+    /**
+     * Flag indicating that this {@code PhoneAccount} can act as a call manager for traditional
+     * SIM-based telephony calls. The {@link ConnectionService} associated with this phone-account
+     * will be allowed to manage SIM-based phone calls including using its own proprietary
+     * phone-call implementation (like VoIP calling) to make calls instead of the telephony stack.
+     * When a user opts to place a call using the SIM-based telephony stack, the connection-service
+     * associated with this phone-account will be attempted first if the user has explicitly
+     * selected it to be used as the default call-manager.
+     * <p>
+     * See {@link #getCapabilities}
+     */
+    public static final int CAPABILITY_SIM_CALL_MANAGER = 0x1;
 
-    private final ComponentName mComponentName;
-    private final String mId;
-    private final Uri mHandle;
-    private final String mLabel;
-    private final String mShortDescription;
-    private final boolean mIsEnabled;
-    private final boolean mIsSystemDefault;
+    /**
+     * Flag indicating that this {@code PhoneAccount} can make phone calls in place of traditional
+     * SIM-based telephony calls. This account will be treated as a distinct method for placing
+     * calls alongside the traditional SIM-based telephony stack. This flag is distinct from
+     * {@link #CAPABILITY_SIM_CALL_MANAGER} in that it is not allowed to manage calls from or use
+     * the built-in telephony stack to place its calls.
+     * <p>
+     * See {@link #getCapabilities}
+     */
+    public static final int CAPABILITY_CALL_PROVIDER = 0x2;
+
+    /**
+     * Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM subscription.
+     * <p>
+     * Only the android framework can set this capability on a phone-account.
+     */
+    public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
+
+    private ComponentName mComponentName;
+    private String mId;
+    private Uri mHandle;
+    private int mCapabilities;
 
     public PhoneAccount(
             ComponentName componentName,
             String id,
             Uri handle,
-            String label,
-            String shortDescription,
-            boolean isEnabled,
-            boolean isSystemDefault) {
+            int capabilities) {
         mComponentName = componentName;
         mId = id;
         mHandle = handle;
-        mLabel = label;
-        mShortDescription = shortDescription;
-        mIsSystemDefault = isSystemDefault;
-        mIsEnabled = isEnabled;
+        mCapabilities = capabilities;
     }
 
     /**
@@ -87,8 +99,8 @@
 
     /**
      * The handle (e.g., a phone number) associated with this {@code PhoneAccount}. This represents
-     * the destination from which outgoing calls using this {@code PhoneAccount} will appear to come
-     * from, if applicable, and the destination to which incoming calls using this
+     * the destination from which outgoing calls using this {@code PhoneAccount} will appear to
+     * come, if applicable, and the destination to which incoming calls using this
      * {@code PhoneAccount} may be addressed.
      *
      * @return A handle expressed as a {@code Uri}, for example, a phone number.
@@ -98,76 +110,23 @@
     }
 
     /**
-     * A short string label describing this {@code PhoneAccount}.
+     * The capabilities of this {@code PhoneAccount}.
      *
-     * @param context The invoking {@code Context}, used for retrieving resources.
-     *
-     * TODO(ihab): If don't need context, remove param
-     *
-     * @return A label for this {@code PhoneAccount}.
+     * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities.
      */
-    public String getLabel(Context context) {
-        return mLabel;
+    public int getCapabilities() {
+        return mCapabilities;
     }
 
-    /**
-     * A short paragraph describing this {@code PhoneAccount}.
-     *
-     * @param context The invoking {@code Context}, used for retrieving resources.
-     *
-     * TODO(ihab): If don't need context, remove param
-     *
-     * @return A description for this {@code PhoneAccount}.
-     */
-    public String getShortDescription(Context context) {
-        return mShortDescription;
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mComponentName) + Objects.hashCode(mId) +
+                Objects.hashCode(mHandle) + mCapabilities;
     }
 
-    // TODO(ihab): Representation of the icons
     //
-    // Refactor to pass a Bitmap (scale it at runtime), but if they don't pass one, fall
-    // back to the android:icon attr in the manifest (<service /> first, <application /> second)
-
-    /**
-     * An icon to represent this {@code PhoneAccount} in a user interface.
-     *
-     * @param context The invoking {@code Context}, used for retrieving resources.
-     *
-     * @return An icon for this {@code PhoneAccount}.
-     */
-    public Drawable getIcon(Context context) {
-        return null;  // TODO(ihab): See above
-    }
-
-    /**
-     * An icon to represent this {@code PhoneAccount} in a user interface.
-     *
-     * @param context The invoking {@code Context}, used for retrieving resources.
-     * @param density A display density from {@link DisplayMetrics}.
-     *
-     * @return An icon for this {@code PhoneAccount}.
-     */
-    public Drawable getIcon(Context context, int density) {
-        return null;  // TODO(ihab): See above
-    }
-
-    /**
-     * Whether this {@code PhoneAccount} is enabled for use.
-     *
-     * @return {@code true} if this {@code PhoneAccount} is enabled.
-     */
-    public boolean isEnabled() {
-        return mIsEnabled;
-    }
-
-    /**
-     * Whether this {@code PhoneAccount} is the system default.
-     *
-     * @return {@code true} if this {@code PhoneAccount} is the system default.
-     */
-    public boolean isSystemDefault() {
-        return mIsSystemDefault;
-    }
+    // Parcelable implementation.
+    //
 
     @Override
     public int describeContents() {
@@ -179,18 +138,16 @@
         out.writeParcelable(mComponentName, flags);
         out.writeString(mId);
         out.writeString(mHandle != null ? mHandle.toString() : "");
-        out.writeString(mLabel);
-        out.writeString(mShortDescription);
-        out.writeInt(mIsEnabled ? 1 : 0);
-        out.writeInt(mIsSystemDefault ? 1 : 0);
+        out.writeInt(mCapabilities);
     }
 
-    public static final Creator<PhoneAccount> CREATOR
-            = new Creator<PhoneAccount>() {
+    public static final Creator<PhoneAccount> CREATOR = new Creator<PhoneAccount>() {
+        @Override
         public PhoneAccount createFromParcel(Parcel in) {
             return new PhoneAccount(in);
         }
 
+        @Override
         public PhoneAccount[] newArray(int size) {
             return new PhoneAccount[size];
         }
@@ -201,22 +158,6 @@
         mId = in.readString();
         String uriString = in.readString();
         mHandle = uriString.length() > 0 ? Uri.parse(uriString) : null;
-        mLabel = in.readString();
-        mShortDescription = in.readString();
-        mIsEnabled = in.readInt() == 1;
-        mIsSystemDefault = in.readInt() == 1;
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        return
-                other instanceof PhoneAccount &&
-                Objects.equals(mComponentName, ((PhoneAccount) other).mComponentName) &&
-                Objects.equals(mId, ((PhoneAccount) other).mId);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(mComponentName) + Objects.hashCode(mId);
+        mCapabilities = in.readInt();
     }
 }
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.aidl b/telecomm/java/android/telecomm/PhoneAccountMetadata.aidl
similarity index 77%
rename from telecomm/java/android/telecomm/CallServiceDescriptor.aidl
rename to telecomm/java/android/telecomm/PhoneAccountMetadata.aidl
index f517c73..55b8900 100644
--- a/telecomm/java/android/telecomm/CallServiceDescriptor.aidl
+++ b/telecomm/java/android/telecomm/PhoneAccountMetadata.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright 2014, The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      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,
@@ -16,4 +16,7 @@
 
 package android.telecomm;
 
-parcelable CallServiceDescriptor;
+/**
+ * {@hide}
+  */
+parcelable PhoneAccountMetadata;
diff --git a/telecomm/java/android/telecomm/PhoneAccountMetadata.java b/telecomm/java/android/telecomm/PhoneAccountMetadata.java
new file mode 100644
index 0000000..20a4d47
--- /dev/null
+++ b/telecomm/java/android/telecomm/PhoneAccountMetadata.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.MissingResourceException;
+
+/**
+ * Provides user interface description information for a {@code PhoneAccount}.
+ */
+public class PhoneAccountMetadata implements Parcelable {
+    private PhoneAccount mAccount;
+    private int mIconResId;
+    private String mLabel;
+    private String mShortDescription;
+
+    public PhoneAccountMetadata(
+            PhoneAccount account,
+            int iconResId,
+            String label,
+            String shortDescription) {
+        mAccount = account;
+        mIconResId = iconResId;
+        mLabel = label;
+        mShortDescription = shortDescription;
+    }
+
+    /**
+     * The {@code PhoneAccount} to which this metadata pertains.
+     *
+     * @return A {@code PhoneAccount}.
+     */
+    public PhoneAccount getAccount() {
+        return mAccount;
+    }
+
+    /**
+     * A short string label describing a {@code PhoneAccount}.
+     *
+     * @return A label for this {@code PhoneAccount}.
+     */
+    public String getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * A short paragraph describing a {@code PhoneAccount}.
+     *
+     * @return A description for this {@code PhoneAccount}.
+     */
+    public String getShortDescription() {
+        return mShortDescription;
+    }
+
+    /**
+     * An icon to represent this {@code PhoneAccount} in a user interface.
+     *
+     * @return An icon for this {@code PhoneAccount}.
+     */
+    public Drawable getIcon(Context context) {
+        return getIcon(context, mIconResId);
+    }
+
+    private Drawable getIcon(Context context, int resId) {
+        Context packageContext;
+        try {
+            packageContext = context.createPackageContext(
+                    mAccount.getComponentName().getPackageName(), 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(this, "Cannot find package %s", mAccount.getComponentName().getPackageName());
+            return null;
+        }
+        try {
+            return packageContext.getResources().getDrawable(resId);
+        } catch (MissingResourceException e) {
+            Log.e(this, e, "Cannot find icon %d in package %s",
+                    resId, mAccount.getComponentName().getPackageName());
+            return null;
+        }
+    }
+
+    //
+    // Parcelable implementation
+    //
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(mAccount, 0);
+        out.writeInt(mIconResId);
+        out.writeString(mLabel);
+        out.writeString(mShortDescription);
+    }
+
+    public static final Creator<PhoneAccountMetadata> CREATOR
+            = new Creator<PhoneAccountMetadata>() {
+        @Override
+        public PhoneAccountMetadata createFromParcel(Parcel in) {
+            return new PhoneAccountMetadata(in);
+        }
+
+        @Override
+        public PhoneAccountMetadata[] newArray(int size) {
+            return new PhoneAccountMetadata[size];
+        }
+    };
+
+    private PhoneAccountMetadata(Parcel in) {
+        mAccount = in.readParcelable(getClass().getClassLoader());
+        mIconResId = in.readInt();
+        mLabel = in.readString();
+        mShortDescription = in.readString();
+    }
+}
diff --git a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
index 856d321..a49076a 100644
--- a/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
+++ b/telecomm/java/android/telecomm/RemoteCallVideoProvider.java
@@ -20,63 +20,92 @@
 import android.os.RemoteException;
 import android.view.Surface;
 
-import com.android.internal.telecomm.ICallVideoClient;
 import com.android.internal.telecomm.ICallVideoProvider;
 
-public class RemoteCallVideoProvider implements IBinder.DeathRecipient {
+public class RemoteCallVideoProvider {
     private final ICallVideoProvider mCallVideoProvider;
 
+    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            mCallVideoProvider.asBinder().unlinkToDeath(this, 0);
+        }
+    };
+
+    /** {@hide} */
     RemoteCallVideoProvider(ICallVideoProvider callVideoProvider) throws RemoteException {
         mCallVideoProvider = callVideoProvider;
-        mCallVideoProvider.asBinder().linkToDeath(this, 0);
+        mCallVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
     }
 
-    @Override
-    public void binderDied() {
-        mCallVideoProvider.asBinder().unlinkToDeath(this, 0);
-    }
-
-    public void setCallVideoClient(CallVideoClient callVideoClient) throws RemoteException {
-        mCallVideoProvider.setCallVideoClient(callVideoClient.getBinder());
+    public void setCallVideoClient(CallVideoClient callVideoClient) {
+        try {
+            mCallVideoProvider.setCallVideoClient(callVideoClient.getBinder());
+        } catch (RemoteException e) {
+        }
     }
 
     public void setCamera(String cameraId) throws RemoteException {
         mCallVideoProvider.setCamera(cameraId);
     }
 
-    public void setPreviewSurface(Surface surface) throws RemoteException {
-        mCallVideoProvider.setPreviewSurface(surface);
+    public void setPreviewSurface(Surface surface) {
+        try {
+            mCallVideoProvider.setPreviewSurface(surface);
+        } catch (RemoteException e) {
+        }
     }
 
-    public void setDisplaySurface(Surface surface) throws RemoteException {
-        mCallVideoProvider.setDisplaySurface(surface);
+    public void setDisplaySurface(Surface surface) {
+        try {
+            mCallVideoProvider.setDisplaySurface(surface);
+        } catch (RemoteException e) {
+        }
     }
 
-    public void setDeviceOrientation(int rotation) throws RemoteException {
-        mCallVideoProvider.setDeviceOrientation(rotation);
+    public void setDeviceOrientation(int rotation) {
+        try {
+            mCallVideoProvider.setDeviceOrientation(rotation);
+        } catch (RemoteException e) {
+        }
     }
 
     public void setZoom(float value) throws RemoteException {
         mCallVideoProvider.setZoom(value);
     }
 
-    public void sendSessionModifyRequest(VideoCallProfile requestProfile) throws RemoteException {
-        mCallVideoProvider.sendSessionModifyRequest(requestProfile);
+    public void sendSessionModifyRequest(VideoCallProfile requestProfile) {
+        try {
+            mCallVideoProvider.sendSessionModifyRequest(requestProfile);
+        } catch (RemoteException e) {
+        }
     }
 
-    public void sendSessionModifyResponse(VideoCallProfile responseProfile) throws RemoteException {
-        mCallVideoProvider.sendSessionModifyResponse(responseProfile);
+    public void sendSessionModifyResponse(VideoCallProfile responseProfile) {
+        try {
+            mCallVideoProvider.sendSessionModifyResponse(responseProfile);
+        } catch (RemoteException e) {
+        }
     }
 
-    public void requestCameraCapabilities() throws RemoteException {
-        mCallVideoProvider.requestCameraCapabilities();
+    public void requestCameraCapabilities() {
+        try {
+            mCallVideoProvider.requestCameraCapabilities();
+        } catch (RemoteException e) {
+        }
     }
 
-    public void requestCallDataUsage() throws RemoteException {
-        mCallVideoProvider.requestCallDataUsage();
+    public void requestCallDataUsage() {
+        try {
+            mCallVideoProvider.requestCallDataUsage();
+        } catch (RemoteException e) {
+        }
     }
 
-    public void setPauseImage(String uri) throws RemoteException {
-        mCallVideoProvider.setPauseImage(uri);
+    public void setPauseImage(String uri) {
+        try {
+            mCallVideoProvider.setPauseImage(uri);
+        } catch (RemoteException e) {
+        }
     }
 }
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index a436af2..430133c 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -266,10 +266,7 @@
                 mComponentName,
                 null /* id */,
                 null /* handle */,
-                "" /* label */,
-                "" /* shortDescription */,
-                true /* isEnabled */,
-                false /* isSystemDefault */));
+                0 /* capabilities */));
         return accounts;
     }
 
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
index b9fb40c..a94841f 100644
--- a/telecomm/java/android/telecomm/TelecommConstants.java
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -16,6 +16,7 @@
 
 package android.telecomm;
 
+import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Bundle;
 import android.telephony.TelephonyManager;
@@ -31,9 +32,9 @@
      * to find and bind to the appropriate {@link android.telecomm.ConnectionService} which
      * Telecomm will ultimately use to control and get information about the call.</p>
      *
-     * <p>Input: get*Extra field {@link #EXTRA_CALL_SERVICE_DESCRIPTOR} contains the component name
-     * of the {@link android.telecomm.ConnectionService} that Telecomm should bind to. Telecomm
-     * will then ask the call service for more information about the call prior to showing any UI.
+     * <p>Input: get*Extra field {@link #EXTRA_PHONE_ACCOUNT} contains the component name of the
+     * {@link android.telecomm.ConnectionService} that Telecomm should bind to. Telecomm will then
+     * ask the connection service for more information about the call prior to showing any UI.
      *
      * TODO(santoscordon): Needs permissions.
      * TODO(santoscordon): Consider moving this into a simple method call on a system service.
@@ -41,16 +42,17 @@
     public static final String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
 
     /**
-     * The service action used to bind to {@link CallServiceProvider} implementations.
-     */
-    public static final String ACTION_CALL_SERVICE_PROVIDER = CallServiceProvider.class.getName();
-
-    /**
      * The service action used to bind to {@link ConnectionService} implementations.
      */
     public static final String ACTION_CONNECTION_SERVICE = ConnectionService.class.getName();
 
     /**
+     * The {@link Intent} action used to configure a {@link ConnectionService}.
+     */
+    public static final String ACTION_CONNECTION_SERVICE_CONFIGURE =
+            "android.intent.action.CONNECTION_SERVICE_CONFIGURE";
+
+    /**
      * Optional extra for {@link Intent#ACTION_CALL} containing a boolean that determines whether
      * the speakerphone should be automatically turned on for an outgoing call.
      */
@@ -69,11 +71,15 @@
             "android.intent.extra.START_CALL_WITH_VIDEO_STATE";
 
     /**
-     * Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that
-     * describes the call service to use for the incoming call.
+     * The extra used with an {@link android.content.Intent#ACTION_CALL},
+     * {@link #ACTION_INCOMING_CALL}, {@link android.content.Intent#ACTION_DIAL} {@code Intent} to
+     * specify a {@link PhoneAccount} to use when making the call.
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getParcelableExtra(String)}.
      */
-    public static final String EXTRA_CALL_SERVICE_DESCRIPTOR =
-            "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
+    public static final String EXTRA_PHONE_ACCOUNT = "android.intent.extra.PHONE_ACCOUNT";
 
     /**
      * Optional extra for {@link #ACTION_INCOMING_CALL} containing a {@link Bundle} which contains
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index 1bb18f2..fcd2eba 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -23,31 +23,30 @@
 
 import com.android.internal.telecomm.ITelecommService;
 
+import java.util.List;
+
 /**
  * Provides access to Telecomm-related functionality.
  * TODO(santoscordon): Move this all into PhoneManager.
  * @hide
  */
 public class TelecommManager {
+
+    /**
+     * The extra used with an {@link android.content.Intent#ACTION_CALL} or
+     * {@link android.content.Intent#ACTION_DIAL} {@code Intent} to specify a {@link PhoneAccount}
+     * to use when making the call.
+     *
+     * <p class="note">
+     * Retrieve with
+     * {@link android.content.Intent#getParcelableExtra(String)}.
+     */
+    public static final String EXTRA_PHONE_ACCOUNT = "account";
+
     private static final String TAG = "TelecommManager";
     private static final String TELECOMM_SERVICE_NAME = "telecomm";
 
     private final Context mContext;
-    private final ITelecommService mService;
-
-    /**
-     * @hide
-     */
-    public TelecommManager(Context context, ITelecommService service) {
-        Context appContext = context.getApplicationContext();
-        if (appContext != null) {
-            mContext = appContext;
-        } else {
-            mContext = context;
-        }
-
-        mService = service;
-    }
 
     /**
      * @hide
@@ -59,6 +58,103 @@
     /**
      * @hide
      */
+    public TelecommManager(Context context) {
+        Context appContext = context.getApplicationContext();
+        if (appContext != null) {
+            mContext = appContext;
+        } else {
+            mContext = context;
+        }
+    }
+
+    /**
+     * Return a list of {@link PhoneAccount}s which can be used to make and receive phone calls.
+     *
+     * @see #EXTRA_PHONE_ACCOUNT
+     * @return A list of {@code PhoneAccount} objects.
+     */
+    public List<PhoneAccount> getEnabledPhoneAccounts() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().getEnabledPhoneAccounts();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#getEnabledPhoneAccounts", e);
+        }
+        return null;
+    }
+
+    /**
+     * Return the metadata for a specified {@link PhoneAccount}. Metadata includes resources which
+     * can be used in a user interface.
+     *
+     * @param account The {@link PhoneAccount}.
+     *
+     * @return The metadata for the account.
+     */
+    public PhoneAccountMetadata getPhoneAccountMetadata(PhoneAccount account) {
+        try {
+            if (isServiceConnected()) {
+                return getTelecommService().getPhoneAccountMetadata(account);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#getPhoneAccountMetadata", e);
+        }
+        return null;
+    }
+
+    /**
+     * Register a {@link PhoneAccount} for use by the system.
+     *
+     * @param account The {@link PhoneAccount}.
+     * @param metadata The metadata for the account.
+     */
+    public void registerPhoneAccount(PhoneAccount account, PhoneAccountMetadata metadata) {
+        try {
+            if (isServiceConnected()) {
+                getTelecommService().registerPhoneAccount(account, metadata);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#registerPhoneAccount", e);
+        }
+    }
+
+    /**
+     * Remove a {@link PhoneAccount} registration from the system.
+     *
+     * @param account An Account.
+     */
+    public void unregisterPhoneAccount(PhoneAccount account) {
+        try {
+            if (isServiceConnected()) {
+                getTelecommService().unregisterPhoneAccount(account);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#unregisterPhoneAccount", e);
+        }
+    }
+
+    /**
+     * Remove all Accounts for a given package from the system.
+     *
+     * @param packageName A package name that may have registered Accounts.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void clearAccounts(String packageName) {
+        try {
+            if (isServiceConnected()) {
+                getTelecommService().clearAccounts(packageName);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelecommService#clearAccounts", e);
+        }
+    }
+
+    /**
+     * @hide
+     */
     @SystemApi
     public ComponentName getDefaultPhoneApp() {
         try {
@@ -108,7 +204,7 @@
 
     /**
      * Ends an ongoing call. TODO(santoscordon): L-release - need to convert all invocations of
-     * ITelephony#endCall to use this method (clockwork & gearhead).
+     * ITelecommService#endCall to use this method (clockwork & gearhead).
      *
      * @hide
      */
@@ -127,7 +223,7 @@
     /**
      * If there is a ringing incoming call, this method accepts the call on behalf of the user.
      * TODO(santoscordon): L-release - need to convert all invocation of
-     * ITelephony#answerRingingCall to use this method (clockwork & gearhead).
+     * ITelecommService#answerRingingCall to use this method (clockwork & gearhead).
      *
      * @hide
      */
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl
deleted file mode 100644
index 10d73be..0000000
--- a/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telecomm;
-
-import android.os.IBinder;
-import android.telecomm.CallServiceDescriptor;
-import java.util.List;
-
-/**
- * Internal remote interface for call service lookup response.
- *
- * @see android.telecomm.CallServiceLookupResponse
- *
- * @hide
- */
-oneway interface ICallServiceLookupResponse {
-    void setCallServiceDescriptors(in List<CallServiceDescriptor> callServiceDescriptors);
-}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl
deleted file mode 100644
index 96daeed..0000000
--- a/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telecomm;
-
-import android.telecomm.CallServiceDescriptor;
-
-import com.android.internal.telecomm.ICallServiceLookupResponse;
-
-/**
- * Internal remote interface for call service providers.
- *
- * @see android.telecomm.CallServiceProvider
- *
- * @hide
- */
-oneway interface ICallServiceProvider {
-    void lookupCallServices(in ICallServiceLookupResponse response);
-}
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 30e4bdc..3334385 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.telecomm.PhoneAccount;
+import android.telecomm.PhoneAccountMetadata;
 
 /**
  * Interface used to interact with Telecomm. Mostly this is used by TelephonyManager for passing
@@ -33,22 +34,32 @@
     void showCallScreen(boolean showDialpad);
 
     /**
-     * Gets a list of accounts.
+     * @see TelecommManager#getEnabledPhoneAccounts
      */
-    List<PhoneAccount> getAccounts();
+    List<PhoneAccount> getEnabledPhoneAccounts();
 
     /**
-     * Sets the enabled state of a given account.
+     * @see TelecommManager#getPhoneAccountMetadata
      */
-    void setEnabled(in PhoneAccount account, boolean enabled);
+    PhoneAccountMetadata getPhoneAccountMetadata(in PhoneAccount account);
 
     /**
-     * Sets a given account as the system default.
+     * @see TelecommManager#registerPhoneAccount
      */
-    void setSystemDefault(in PhoneAccount account);
+    void registerPhoneAccount(in PhoneAccount account, in PhoneAccountMetadata metadata);
 
     /**
-     * Returns the component name of the default phone application.
+     * @see TelecommManager#unregisterPhoneAccount
+     */
+    void unregisterPhoneAccount(in PhoneAccount account);
+
+    /**
+     * @see TelecommManager#clearAccounts
+     */
+    void clearAccounts(String packageName);
+
+    /**
+     * @see TelecommManager#getDefaultPhoneApp
      */
     ComponentName getDefaultPhoneApp();
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 91ce73a..c1eb843 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -298,17 +298,6 @@
     public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
 
     /**
-     * The lookup key used with an {@link android.content.Intent#ACTION_CALL} or
-     * {@link android.content.Intent#ACTION_DIAL} {@code Intent} for a {@link PhoneAccount}
-     * object indicating a preference when making a phone connection.
-     *
-     * <p class="note">
-     * Retrieve with
-     * {@link android.content.Intent#getParcelableExtra(String)}.
-     */
-    public static final String EXTRA_ACCOUNT = "account";
-
-    /**
      * Broadcast intent action indicating that a precise call state
      * (cellular) on the device has changed.
      *
@@ -3207,42 +3196,6 @@
     }
 
     /**
-     * Return a list of Accounts that can be used to indicate a preference when making
-     * a phone call.
-     *
-     * @see #EXTRA_ACCOUNT
-     * @return A list of {@code Accouint} objects.
-     */
-    public List<PhoneAccount> getAccounts() {
-        try {
-            return getTelecommService().getAccounts();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#getAccounts", e);
-        }
-        return null;
-    }
-
-    /** @hide */
-    @SystemApi
-    public void setEnabled(PhoneAccount account, boolean enabled) {
-        try {
-            getTelecommService().setEnabled(account, enabled);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#setEnabled", e);
-        }
-    }
-
-    /** @hide */
-    @SystemApi
-    public void setSystemDefault(PhoneAccount account) {
-        try {
-            getTelecommService().setSystemDefault(account);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#setSystemDefault", e);
-        }
-    }
-
-    /**
      * Set whether Android should display a simplified Mobile Network Settings UI.
      * The setting won't be persisted during power cycle.
      * <p>
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
deleted file mode 100644
index bcf2d81..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallProvider;
-
-/**
- * Interface provided to ThirdPartyCallService. The service can use this to notify the listener of
- * changes to the call state.
- */
-oneway interface IThirdPartyCallListener {
-    /**
-     * Called by the service when a call provider is available to perform the outgoing or incoming
-     * call.
-     */
-    void onCallProviderAttached(IThirdPartyCallProvider callProvider);
-
-    /**
-     * Notifies the listener that ringing has started for this call.
-     */
-    void onRingingStarted();
-
-    /**
-     * Notifies the listener that the call has been successfully established.
-     */
-    void onCallEstablished();
-
-    /**
-     * Notifies the listener that the call has ended.
-     */
-    void onCallEnded(int reason);
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
deleted file mode 100644
index 9d595b0..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-import com.android.internal.telephony.IThirdPartyCallSendDtmfCallback;
-
-/**
- * Interface sent to ThirdPartyCallListener.onCallProviderAttached. This is used to control an
- * outgoing or incoming call.
- */
-oneway interface IThirdPartyCallProvider {
-    /**
-     * Mutes or unmutes the call.
-     */
-    void mute(boolean shouldMute);
-
-    /**
-     * Ends the current call. If this is an unanswered incoming call then the call is rejected (for
-     * example, a notification is sent to a server that the user declined the call).
-     */
-    void hangup();
-
-    /**
-     * Accepts the incoming call.
-     */
-    void incomingCallAccept();
-
-    /**
-     * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
-     */
-    void sendDtmf(char c, IThirdPartyCallSendDtmfCallback callback);
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl
deleted file mode 100644
index 3a02b06..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-/**
- * Callback interface for when DTMF has been sent.
- */
-oneway interface IThirdPartyCallSendDtmfCallback {
-    /**
-     * Called when the DTMF code has been sent.
-     */
-    void onSendDtmfCompleted();
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
deleted file mode 100644
index 597567a..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-
-/**
- * Interface provided by a service to start outgoing calls and attach to incoming calls.
- */
-oneway interface IThirdPartyCallService {
-    /**
-     * Call to start a new outgoing call.
-     */
-    void outgoingCallInitiate(IThirdPartyCallListener listener, String number);
-
-    /**
-     * Call to attach to an incoming call. This is in response to a call to
-     * TelephonyManager.newIncomingThirdPartyCall.
-     */
-    void incomingCallAttach(IThirdPartyCallListener listener, String callId);
-}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index a54936b..2ebce9b 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -175,6 +175,11 @@
     }
 
     @Override
+    public File getNoBackupFilesDir() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public File getExternalFilesDir(String type) {
         throw new UnsupportedOperationException();
     }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index a14714a..648c418 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -31,6 +31,7 @@
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
+import android.content.pm.KeySet;
 import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
@@ -616,6 +617,26 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public KeySet getKeySetByAlias(String packageName, String alias) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public KeySet getSigningKeySet(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isSignedBy(String packageName, KeySet ks) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isSignedByExactly(String packageName, KeySet ks) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * @hide
      */
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index 802f473..9cbb455 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -18,12 +18,14 @@
 
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
+import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -43,7 +45,7 @@
     protected MediaController.TransportControls mTransportControls;
 
     private final Intent mServiceIntent;
-    private Context mContext;
+    private Activity mContext;
     private Listener mListener;
     private SessionCallback mControllerCb;
     private MediaSessionManager mManager;
@@ -51,7 +53,7 @@
 
     private boolean mResumed;
 
-    public PlayerController(Context context, Intent serviceIntent) {
+    public PlayerController(Activity context, Intent serviceIntent) {
         mContext = context;
         if (serviceIntent == null) {
             mServiceIntent = new Intent(mContext, PlayerService.class);
@@ -140,6 +142,7 @@
             mBinder = null;
             mController = null;
             mTransportControls = null;
+            mContext.setMediaController(null);
             Log.d(TAG, "Disconnected from PlayerService");
 
             if (mListener != null) {
@@ -151,12 +154,15 @@
         public void onServiceConnected(ComponentName name, IBinder service) {
             mBinder = IPlayerService.Stub.asInterface(service);
             Log.d(TAG, "service is " + service + " binder is " + mBinder);
+            MediaSession.Token token;
             try {
-                mController = MediaController.fromToken(mBinder.getSessionToken());
+                token = mBinder.getSessionToken();
             } catch (RemoteException e) {
                 Log.e(TAG, "Error getting session", e);
                 return;
             }
+            mController = MediaController.fromToken(token);
+            mContext.setMediaController(mController);
             mController.addCallback(mControllerCb, mHandler);
             mTransportControls = mController.getTransportControls();
             Log.d(TAG, "Ready to use PlayerService");
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 7c0eabe..78353b2 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.support.media.protocols.MediaPlayerProtocol;
 import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
+import android.os.SystemClock;
 import android.util.Log;
 import android.view.KeyEvent;
 
@@ -59,9 +60,9 @@
         mRenderer = new LocalRenderer(context, null);
         mCallback = new SessionCb();
         mRenderListener = new RenderListener();
-        mPlaybackState = new PlaybackState();
-        mPlaybackState.setActions(PlaybackState.ACTION_PAUSE
-                | PlaybackState.ACTION_PLAY);
+        PlaybackState.Builder psBob = new PlaybackState.Builder();
+        psBob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
+        mPlaybackState = psBob.build();
 
         mRenderer.registerListener(mRenderListener);
     }
@@ -131,7 +132,10 @@
     private void updateState(int newState) {
         float rate = newState == PlaybackState.STATE_PLAYING ? 1 : 0;
         long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
-        mPlaybackState.setState(newState, position, rate);
+        PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+        bob.setState(newState, position, rate, SystemClock.elapsedRealtime());
+        bob.setErrorMessage(null);
+        mPlaybackState = bob.build();
         mSession.setPlaybackState(mPlaybackState);
     }
 
@@ -144,10 +148,12 @@
         @Override
         public void onError(int type, int extra, Bundle extras, Throwable error) {
             Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
-            mPlaybackState.setState(PlaybackState.STATE_ERROR, -1, 0);
+            PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+            bob.setState(PlaybackState.STATE_ERROR, -1, 0, 0);
             if (error != null) {
-                mPlaybackState.setErrorMessage(error.getLocalizedMessage());
+                bob.setErrorMessage(error.getLocalizedMessage());
             }
+            mPlaybackState = bob.build();
             mSession.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
@@ -156,36 +162,41 @@
 
         @Override
         public void onStateChanged(int newState) {
-            if (newState != Renderer.STATE_ERROR) {
-                mPlaybackState.setErrorMessage(null);
-            }
             long position = -1;
             if (mRenderer != null) {
                 position = mRenderer.getSeekPosition();
             }
+            int pbState;
+            float rate = 0;
+            String errorMsg = null;
             switch (newState) {
                 case Renderer.STATE_ENDED:
                 case Renderer.STATE_STOPPED:
-                    mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0);
+                    pbState = PlaybackState.STATE_STOPPED;
                     break;
                 case Renderer.STATE_INIT:
                 case Renderer.STATE_PREPARING:
-                    mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0);
+                    pbState = PlaybackState.STATE_BUFFERING;
                     break;
                 case Renderer.STATE_ERROR:
-                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
+                    pbState = PlaybackState.STATE_ERROR;
                     break;
                 case Renderer.STATE_PAUSED:
-                    mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
+                    pbState = PlaybackState.STATE_PAUSED;
                     break;
                 case Renderer.STATE_PLAYING:
-                    mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1);
+                    pbState = PlaybackState.STATE_PLAYING;
+                    rate = 1;
                     break;
                 default:
-                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
-                    mPlaybackState.setErrorMessage("unkown state");
+                    pbState = PlaybackState.STATE_ERROR;
+                    errorMsg = "unknown state";
                     break;
             }
+            PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+            bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
+            bob.setErrorMessage(errorMsg);
+            mPlaybackState = bob.build();
             mSession.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
@@ -200,7 +211,10 @@
         public void onFocusLost() {
             Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
             long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
-            mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
+            PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+            bob.setState(PlaybackState.STATE_PAUSED, position, 0, SystemClock.elapsedRealtime());
+            bob.setErrorMessage(null);
+            mPlaybackState = bob.build();
             mSession.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
index 2e1478b..5845e48 100644
--- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -29,6 +29,9 @@
 import android.support.media.protocols.MediaPlayerProtocol;
 import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
 import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.SystemClock;
 import android.util.Log;
 
 import com.android.onemedia.playback.LocalRenderer;
@@ -60,9 +63,9 @@
         mHandler = new Handler();
         mRenderer = new LocalRenderer(this, null);
         mRenderListener = new RenderListener();
-        mPlaybackState = new PlaybackState();
-        mPlaybackState.setActions(PlaybackState.ACTION_PAUSE
-                | PlaybackState.ACTION_PLAY);
+        PlaybackState.Builder bob = new PlaybackState.Builder();
+        bob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
+        mPlaybackState = bob.build();
 
         mRenderer.registerListener(mRenderListener);
     }
@@ -178,36 +181,41 @@
 
         @Override
         public void onStateChanged(int newState) {
-            if (newState != Renderer.STATE_ERROR) {
-                mPlaybackState.setErrorMessage(null);
-            }
             long position = -1;
             if (mRenderer != null) {
                 position = mRenderer.getSeekPosition();
             }
+            int pbState;
+            float rate = 0;
+            String errorMsg = null;
             switch (newState) {
                 case Renderer.STATE_ENDED:
                 case Renderer.STATE_STOPPED:
-                    mPlaybackState.setState(PlaybackState.STATE_STOPPED, position, 0);
+                    pbState = PlaybackState.STATE_STOPPED;
                     break;
                 case Renderer.STATE_INIT:
                 case Renderer.STATE_PREPARING:
-                    mPlaybackState.setState(PlaybackState.STATE_BUFFERING, position, 0);
+                    pbState = PlaybackState.STATE_BUFFERING;
                     break;
                 case Renderer.STATE_ERROR:
-                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
+                    pbState = PlaybackState.STATE_ERROR;
                     break;
                 case Renderer.STATE_PAUSED:
-                    mPlaybackState.setState(PlaybackState.STATE_PAUSED, position, 0);
+                    pbState = PlaybackState.STATE_PAUSED;
                     break;
                 case Renderer.STATE_PLAYING:
-                    mPlaybackState.setState(PlaybackState.STATE_PLAYING, position, 1);
+                    pbState = PlaybackState.STATE_PLAYING;
+                    rate = 1;
                     break;
                 default:
-                    mPlaybackState.setState(PlaybackState.STATE_ERROR, position, 0);
-                    mPlaybackState.setErrorMessage("unkown state");
+                    pbState = PlaybackState.STATE_ERROR;
+                    errorMsg = "unknown state";
                     break;
             }
+            PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+            bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
+            bob.setErrorMessage(errorMsg);
+            mPlaybackState = bob.build();
 
             sendStatusUpdate(mPlaybackState.getState());
         }
@@ -218,8 +226,9 @@
 
         @Override
         public void onFocusLost() {
-            Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
-            mPlaybackState.setState(PlaybackState.STATE_PAUSED, mRenderer.getSeekPosition(), 0);
+            Log.d(TAG, "Focus lost, pausing");
+            // Don't update state here, we'll get a separate call to
+            // onStateChanged when it pauses
             mRenderer.onPause();
         }