Merge "Speed up brightness transition if auto brightness adjustment is changed"
diff --git a/Android.mk b/Android.mk
index 89b2884..9828ea6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -147,6 +147,8 @@
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
core/java/android/hardware/hdmi/IHdmiCecListener.aidl \
core/java/android/hardware/hdmi/IHdmiCecService.aidl \
+ core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
+ core/java/android/hardware/hdmi/IHdmiControlService.aidl \
core/java/android/hardware/input/IInputManager.aidl \
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
core/java/android/hardware/location/IFusedLocationHardware.aidl \
@@ -324,7 +326,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/ITelephonyListener.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 \
@@ -333,7 +334,7 @@
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
- wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl \
+ wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
wifi/java/android/net/wifi/IWifiScanner.aidl \
packages/services/PacProcessor/com/android/net/IProxyService.aidl \
diff --git a/api/current.txt b/api/current.txt
index 91f20b7..eda087d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27,11 +27,9 @@
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
- field public static final java.lang.String BIND_ROUTE_PROVIDER = "android.permission.BIND_ROUTE_PROVIDER";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
- field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
@@ -1017,7 +1015,6 @@
field public static final int selectableItemBackground = 16843534; // 0x101030e
field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
- field public static final int sessionService = 16843841; // 0x1010441
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int shadowColor = 16843105; // 0x1010161
field public static final int shadowDx = 16843106; // 0x1010162
@@ -3238,7 +3235,6 @@
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
- method public android.app.VoiceInteractor getVoiceInteractor();
method public final int getVolumeControlStream();
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
@@ -3250,7 +3246,6 @@
method public boolean isFinishing();
method public boolean isImmersive();
method public boolean isTaskRoot();
- method public boolean isVoiceInteraction();
method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public boolean moveTaskToBack(boolean);
method public boolean navigateUpTo(android.content.Intent);
@@ -3352,12 +3347,12 @@
method public final void setProgressBarIndeterminate(boolean);
method public final void setProgressBarIndeterminateVisibility(boolean);
method public final void setProgressBarVisibility(boolean);
- method public void setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
method public void setRequestedOrientation(int);
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method public final void setSecondaryProgress(int);
method public void setSharedElementListener(android.app.SharedElementListener);
+ method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
method public void setTitle(java.lang.CharSequence);
method public void setTitle(int);
method public deprecated void setTitleColor(int);
@@ -3482,7 +3477,6 @@
method public void readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
- field public android.app.ActivityManager.RecentsActivityValues activityValues;
field public android.content.Intent baseIntent;
field public java.lang.CharSequence description;
field public int id;
@@ -3490,21 +3484,6 @@
field public int persistentId;
}
- public static class ActivityManager.RecentsActivityValues implements android.os.Parcelable {
- ctor public ActivityManager.RecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
- ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap, int);
- ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap);
- ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence);
- ctor public ActivityManager.RecentsActivityValues();
- method public int describeContents();
- method public void readFromParcel(android.os.Parcel);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public int colorPrimary;
- field public android.graphics.Bitmap icon;
- field public java.lang.CharSequence label;
- }
-
public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
ctor public ActivityManager.RunningAppProcessInfo();
ctor public ActivityManager.RunningAppProcessInfo(java.lang.String, int, java.lang.String[]);
@@ -3574,6 +3553,21 @@
field public android.content.ComponentName topActivity;
}
+ public static class ActivityManager.TaskDescription implements android.os.Parcelable {
+ ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+ ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+ ctor public ActivityManager.TaskDescription(java.lang.String);
+ ctor public ActivityManager.TaskDescription();
+ ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
+ method public int describeContents();
+ method public android.graphics.Bitmap getIcon();
+ method public java.lang.String getLabel();
+ method public int getPrimaryColor();
+ method public void readFromParcel(android.os.Parcel);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public class ActivityOptions {
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
@@ -4515,6 +4509,7 @@
ctor public Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Action clone();
method public int describeContents();
+ method public android.os.Bundle getExtras();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public android.app.PendingIntent actionIntent;
@@ -4522,6 +4517,14 @@
field public java.lang.CharSequence title;
}
+ public static class Notification.Action.Builder {
+ ctor public Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public Notification.Action.Builder(android.app.Notification.Action);
+ method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
+ method public android.app.Notification.Action build();
+ method public android.os.Bundle getExtras();
+ }
+
public static class Notification.BigPictureStyle extends android.app.Notification.Style {
ctor public Notification.BigPictureStyle();
ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
@@ -4542,6 +4545,7 @@
public static class Notification.Builder {
ctor public Notification.Builder(android.content.Context);
method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+ method public android.app.Notification.Builder addAction(android.app.Notification.Action);
method public android.app.Notification.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Builder addPerson(java.lang.String);
method public android.app.Notification build();
@@ -4902,29 +4906,6 @@
field public static final int MODE_NIGHT_YES = 2; // 0x2
}
- public class VoiceInteractor {
- method public boolean submitRequest(android.app.VoiceInteractor.Request);
- method public boolean[] supportsCommands(java.lang.String[]);
- }
-
- public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request {
- ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle);
- method public void onCommandResult(android.os.Bundle);
- }
-
- public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request {
- ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle);
- method public void onConfirmationResult(boolean, android.os.Bundle);
- }
-
- public static abstract class VoiceInteractor.Request {
- ctor public VoiceInteractor.Request();
- method public void cancel();
- method public android.app.Activity getActivity();
- method public android.content.Context getContext();
- method public void onCancel();
- }
-
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -5235,7 +5216,7 @@
public abstract class TaskService extends android.app.Service {
ctor public TaskService();
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onStartTask(android.app.task.TaskParams);
+ method public abstract boolean onStartTask(android.app.task.TaskParams);
method public abstract boolean onStopTask(android.app.task.TaskParams);
method public final void taskFinished(android.app.task.TaskParams, boolean);
field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
@@ -6648,6 +6629,7 @@
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
+ field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
@@ -6678,8 +6660,8 @@
field public static final java.lang.String USER_SERVICE = "user";
field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
- field public static final java.lang.String WIFI_HOTSPOT_SERVICE = "wifihotspot";
field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
+ field public static final java.lang.String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
field public static final java.lang.String WIFI_SERVICE = "wifi";
field public static final java.lang.String WINDOW_SERVICE = "window";
}
@@ -7122,7 +7104,6 @@
field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
- field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
field public static final android.os.Parcelable.Creator CREATOR;
field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -12298,12 +12279,16 @@
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
}
+}
+
+package android.hardware.camera2.params {
+
public final class ColorSpaceTransform {
- ctor public ColorSpaceTransform(android.hardware.camera2.Rational[]);
+ ctor public ColorSpaceTransform(android.util.Rational[]);
ctor public ColorSpaceTransform(int[]);
- method public void copyElements(android.hardware.camera2.Rational[], int);
+ method public void copyElements(android.util.Rational[], int);
method public void copyElements(int[], int);
- method public android.hardware.camera2.Rational getElement(int, int);
+ method public android.util.Rational getElement(int, int);
}
public final class Face {
@@ -12323,7 +12308,7 @@
method public int getColumnCount();
method public float getGainFactor(int, int, int);
method public int getGainFactorCount();
- method public android.hardware.camera2.RggbChannelVector getGainFactorVector(int, int);
+ method public android.hardware.camera2.params.RggbChannelVector getGainFactorVector(int, int);
method public int getRowCount();
field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
}
@@ -12332,7 +12317,7 @@
ctor public MeteringRectangle(int, int, int, int, int);
ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
ctor public MeteringRectangle(android.graphics.Rect, int);
- method public boolean equals(android.hardware.camera2.MeteringRectangle);
+ method public boolean equals(android.hardware.camera2.params.MeteringRectangle);
method public int getHeight();
method public int getMeteringWeight();
method public android.graphics.Rect getRect();
@@ -12343,12 +12328,6 @@
method public int getY();
}
- public final class Rational {
- ctor public Rational(int, int);
- method public int getDenominator();
- method public int getNumerator();
- }
-
public final class RggbChannelVector {
ctor public RggbChannelVector(float, float, float, float);
method public void copyTo(float[], int);
@@ -12364,10 +12343,17 @@
field public static final int RED = 0; // 0x0
}
- public final class Size {
- ctor public Size(int, int);
- method public final int getHeight();
- method public final int getWidth();
+ public final class StreamConfigurationMap {
+ method public final int[] getOutputFormats();
+ method public long getOutputMinFrameDuration(int, android.util.Size);
+ method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+ method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+ method public android.util.Size[] getOutputSizes(int);
+ method public long getOutputStallDuration(int, android.util.Size);
+ method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+ method public boolean isOutputSupportedFor(int);
+ method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+ method public boolean isOutputSupportedFor(android.view.Surface);
}
public final class TonemapCurve {
@@ -12384,23 +12370,6 @@
}
-package android.hardware.camera2.params {
-
- public final class StreamConfigurationMap {
- method public final int[] getOutputFormats();
- method public long getOutputMinFrameDuration(int, android.util.Size);
- method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
- method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
- method public android.util.Size[] getOutputSizes(int);
- method public long getOutputStallDuration(int, android.util.Size);
- method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
- method public boolean isOutputSupportedFor(int);
- method public static boolean isOutputSupportedFor(java.lang.Class<T>);
- method public boolean isOutputSupportedFor(android.view.Surface);
- }
-
-}
-
package android.hardware.display {
public final class DisplayManager {
@@ -12534,9 +12503,15 @@
field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_UP = 139; // 0x8b
field public static final int POWER_STATUS_ON = 0; // 0x0
field public static final int POWER_STATUS_STANDBY = 1; // 0x1
+ field public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; // 0x2
+ field public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; // 0x3
field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
- field public static final int POWER_TRANSIENT_TO_ON = 2; // 0x2
- field public static final int POWER_TRANSIENT_TO_STANDBY = 3; // 0x3
+ field public static final int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
+ field public static final int RESULT_EXCEPTION = 5; // 0x5
+ field public static final int RESULT_SOURCE_NOT_AVAILABLE = 2; // 0x2
+ field public static final int RESULT_SUCCESS = 0; // 0x0
+ field public static final int RESULT_TARGET_NOT_AVAILABLE = 3; // 0x3
+ field public static final int RESULT_TIMEOUT = 1; // 0x1
field public static final int UNKNOWN_VENDOR_ID = 16777215; // 0xffffff
}
@@ -12582,6 +12557,27 @@
field public static final byte[] EMPTY_PARAM;
}
+ public final class HdmiControlManager {
+ method public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
+ method public android.hardware.hdmi.HdmiTvClient getTvClient();
+ }
+
+ public final class HdmiPlaybackClient {
+ method public void oneTouchPlay(android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback);
+ method public void queryDisplayStatus(android.hardware.hdmi.HdmiPlaybackClient.DisplayStatusCallback);
+ }
+
+ public static abstract interface HdmiPlaybackClient.DisplayStatusCallback {
+ method public abstract void onComplete(int);
+ }
+
+ public static abstract interface HdmiPlaybackClient.OneTouchPlayCallback {
+ method public abstract void onComplete(int);
+ }
+
+ public final class HdmiTvClient {
+ }
+
}
package android.hardware.input {
@@ -13738,16 +13734,17 @@
ctor public DeniedByServerException(java.lang.String);
}
- public final class DngCreator {
+ public final class DngCreator implements java.lang.AutoCloseable {
ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult);
+ method public void close();
method public android.media.DngCreator setDescription(java.lang.String);
method public android.media.DngCreator setLocation(android.location.Location);
method public android.media.DngCreator setOrientation(int);
method public android.media.DngCreator setThumbnail(android.graphics.Bitmap);
method public android.media.DngCreator setThumbnail(android.media.Image);
- method public void writeByteBuffer(java.io.OutputStream, java.nio.ByteBuffer, int, long) throws java.io.IOException;
+ method public void writeByteBuffer(java.io.OutputStream, android.util.Size, java.nio.ByteBuffer, long) throws java.io.IOException;
method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException;
- method public void writeInputStream(java.io.OutputStream, java.io.InputStream, int, long) throws java.io.IOException;
+ method public void writeInputStream(java.io.OutputStream, android.util.Size, java.io.InputStream, long) throws java.io.IOException;
}
public class ExifInterface {
@@ -14248,6 +14245,49 @@
field public static final java.lang.String KEY_WIDTH = "width";
}
+ public final class MediaMetadata implements android.os.Parcelable {
+ method public boolean containsKey(java.lang.String);
+ method public int describeContents();
+ method public android.graphics.Bitmap getBitmap(java.lang.String);
+ method public long getLong(java.lang.String);
+ method public android.media.Rating getRating(java.lang.String);
+ method public java.lang.String getString(java.lang.String);
+ method public int size();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+ field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+ field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+ field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+ field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+ field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+ field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+ field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+ field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+ field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+ field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+ field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+ field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+ field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+ field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+ field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+ field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+ field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+ field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+ }
+
+ public static final class MediaMetadata.Builder {
+ ctor public MediaMetadata.Builder();
+ ctor public MediaMetadata.Builder(android.media.MediaMetadata);
+ method public android.media.MediaMetadata build();
+ method public android.media.MediaMetadata.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+ method public android.media.MediaMetadata.Builder putLong(java.lang.String, long);
+ method public android.media.MediaMetadata.Builder putRating(java.lang.String, android.media.Rating);
+ method public android.media.MediaMetadata.Builder putString(java.lang.String, java.lang.String);
+ }
+
public abstract class MediaMetadataEditor {
method public synchronized void addEditableKey(int);
method public abstract void apply();
@@ -15343,109 +15383,61 @@
}
-package android.media.routeprovider {
-
- public final class RouteConnection {
- ctor public RouteConnection(android.media.routeprovider.RouteProviderService, android.media.session.RouteInfo);
- method public android.media.routeprovider.RouteInterfaceHandler addRouteInterface(java.lang.String);
- method public android.media.routeprovider.RouteInterfaceHandler getRouteInterface(java.lang.String);
- method public void shutDown();
- }
-
- public final class RouteInterfaceHandler {
- method public void addListener(android.media.routeprovider.RouteInterfaceHandler.CommandListener, android.os.Handler);
- method public java.lang.String getName();
- method public void removeListener(android.media.routeprovider.RouteInterfaceHandler.CommandListener);
- method public void sendEvent(java.lang.String, android.os.Bundle);
- method public static void sendResult(android.os.ResultReceiver, int, android.os.Bundle);
- }
-
- public static abstract class RouteInterfaceHandler.CommandListener {
- ctor public RouteInterfaceHandler.CommandListener();
- method public abstract boolean onCommand(android.media.routeprovider.RouteInterfaceHandler, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- }
-
- public final class RoutePlaybackControlsHandler {
- method public void addListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener);
- method public void addListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener, android.os.Handler);
- method public static android.media.routeprovider.RoutePlaybackControlsHandler addTo(android.media.routeprovider.RouteConnection);
- method public void removeListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener);
- method public void sendPlaybackChangeEvent(int);
- }
-
- public static abstract class RoutePlaybackControlsHandler.Listener extends android.media.routeprovider.RouteInterfaceHandler.CommandListener {
- ctor public RoutePlaybackControlsHandler.Listener();
- method public boolean fastForward();
- method public long getCapabilities();
- method public long getCurrentPosition();
- method public final boolean onCommand(android.media.routeprovider.RouteInterfaceHandler, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- method public boolean pause();
- method public void playNow(java.lang.String, android.os.ResultReceiver);
- method public boolean resume();
- }
-
- public abstract class RouteProviderService extends android.app.Service {
- ctor public RouteProviderService();
- method public abstract android.media.routeprovider.RouteConnection connect(android.media.session.RouteInfo, android.media.routeprovider.RouteRequest);
- method public abstract java.util.List<android.media.session.RouteInfo> getMatchingRoutes(java.util.List<android.media.routeprovider.RouteRequest>);
- method public android.os.IBinder onBind(android.content.Intent);
- method public void updateDiscoveryRequests(java.util.List<android.media.routeprovider.RouteRequest>);
- field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.session.MediaRouteProvider";
- }
-
- public final class RouteRequest implements android.os.Parcelable {
- method public int describeContents();
- method public android.media.session.RouteOptions getConnectionOptions();
- method public android.media.session.SessionInfo getSessionInfo();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
-}
-
package android.media.session {
- public final class MediaMetadata implements android.os.Parcelable {
- method public boolean containsKey(java.lang.String);
- method public int describeContents();
- method public android.graphics.Bitmap getBitmap(java.lang.String);
- method public long getLong(java.lang.String);
- method public android.media.Rating getRating(java.lang.String);
- method public java.lang.String getString(java.lang.String);
- method public int size();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
- field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
- field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
- field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
- field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
- field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
- field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
- field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
- field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
- field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
- field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
- field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
- field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
- field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
- field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
- field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
- field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
- field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
- field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
- field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
- field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+ public final class MediaController {
+ method public void addCallback(android.media.session.MediaController.Callback);
+ method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler);
+ method public static android.media.session.MediaController fromToken(android.media.session.MediaSessionToken);
+ method public android.media.session.TransportController getTransportController();
+ method public void removeCallback(android.media.session.MediaController.Callback);
+ method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public void sendMediaButton(int);
}
- public static final class MediaMetadata.Builder {
- ctor public MediaMetadata.Builder();
- ctor public MediaMetadata.Builder(android.media.session.MediaMetadata);
- method public android.media.session.MediaMetadata build();
- method public android.media.session.MediaMetadata.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
- method public android.media.session.MediaMetadata.Builder putLong(java.lang.String, long);
- method public android.media.session.MediaMetadata.Builder putRating(java.lang.String, android.media.Rating);
- method public android.media.session.MediaMetadata.Builder putString(java.lang.String, java.lang.String);
+ public static abstract class MediaController.Callback {
+ ctor public MediaController.Callback();
+ method public void onEvent(java.lang.String, android.os.Bundle);
+ }
+
+ public final class MediaSession {
+ method public void addCallback(android.media.session.MediaSession.Callback);
+ method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler);
+ method public android.media.session.MediaSessionToken getSessionToken();
+ method public android.media.session.TransportPerformer getTransportPerformer();
+ method public boolean isActive();
+ method public void release();
+ method public void removeCallback(android.media.session.MediaSession.Callback);
+ method public void sendEvent(java.lang.String, android.os.Bundle);
+ method public void setActive(boolean);
+ method public void setFlags(int);
+ field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+ }
+
+ public static abstract class MediaSession.Callback {
+ ctor public MediaSession.Callback();
+ method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public void onMediaButton(android.content.Intent);
+ }
+
+ public final class MediaSessionInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.String getId();
+ method public java.lang.String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public final class MediaSessionManager {
+ method public android.media.session.MediaSession createSession(java.lang.String);
+ method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
+ }
+
+ public class MediaSessionToken implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
public final class PlaybackState implements android.os.Parcelable {
@@ -15476,7 +15468,6 @@
field public static final android.os.Parcelable.Creator CREATOR;
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int PLAYSTATE_BUFFERING = 6; // 0x6
- field public static final int PLAYSTATE_CONNECTING = 8; // 0x8
field public static final int PLAYSTATE_ERROR = 7; // 0x7
field public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4
field public static final int PLAYSTATE_NONE = 0; // 0x0
@@ -15488,160 +15479,11 @@
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
}
- public final class Route {
- method public android.media.session.RouteInterface getInterface(java.lang.String);
- method public android.media.session.RouteOptions getOptions();
- method public android.media.session.RouteInfo getRouteInfo();
- }
-
- public final class RouteInfo implements android.os.Parcelable {
- method public int describeContents();
- method public java.util.List<android.media.session.RouteOptions> getConnectionMethods();
- method public java.lang.String getId();
- method public java.lang.String getName();
- method public java.lang.String getProvider();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public static final class RouteInfo.Builder {
- ctor public RouteInfo.Builder(android.media.session.RouteInfo);
- ctor public RouteInfo.Builder();
- method public android.media.session.RouteInfo.Builder addRouteOptions(android.media.session.RouteOptions);
- method public android.media.session.RouteInfo build();
- method public android.media.session.RouteInfo.Builder clearRouteOptions();
- method public int getOptionsSize();
- method public android.media.session.RouteInfo.Builder setId(java.lang.String);
- method public android.media.session.RouteInfo.Builder setName(java.lang.String);
- }
-
- public final class RouteInterface {
- method public void addListener(android.media.session.RouteInterface.EventListener);
- method public void addListener(android.media.session.RouteInterface.EventListener, android.os.Handler);
- method public void removeListener(android.media.session.RouteInterface.EventListener);
- method public boolean sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- field public static final int RESULT_COMMAND_NOT_SUPPORTED = -3; // 0xfffffffd
- field public static final int RESULT_ERROR = -1; // 0xffffffff
- field public static final int RESULT_INTERFACE_NOT_SUPPORTED = -2; // 0xfffffffe
- field public static final int RESULT_NOT_CONNECTED = -5; // 0xfffffffb
- field public static final int RESULT_ROUTE_IS_STALE = -4; // 0xfffffffc
- field public static final int RESULT_SUCCESS = 1; // 0x1
- }
-
- public static abstract class RouteInterface.EventListener {
- ctor public RouteInterface.EventListener();
- method public abstract void onEvent(java.lang.String, android.os.Bundle);
- }
-
- public final class RouteOptions implements android.os.Parcelable {
- method public int describeContents();
- method public android.os.Bundle getConnectionParams();
- method public java.util.List<java.lang.String> getInterfaceNames();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public static final class RouteOptions.Builder {
- ctor public RouteOptions.Builder();
- method public android.media.session.RouteOptions.Builder addInterface(java.lang.String);
- method public android.media.session.RouteOptions build();
- method public android.media.session.RouteOptions.Builder setParameters(android.os.Bundle);
- }
-
- public final class RoutePlaybackControls {
- method public void addListener(android.media.session.RoutePlaybackControls.Listener);
- method public void addListener(android.media.session.RoutePlaybackControls.Listener, android.os.Handler);
- method public void fastForward();
- method public static android.media.session.RoutePlaybackControls from(android.media.session.Route);
- method public void getCapabilities(android.os.ResultReceiver);
- method public void getCurrentPosition(android.os.ResultReceiver);
- method public void pause();
- method public void playNow(java.lang.String);
- method public void removeListener(android.media.session.RoutePlaybackControls.Listener);
- method public void resume();
- field public static final java.lang.String NAME = "android.media.session.RoutePlaybackControls";
- }
-
- public static abstract class RoutePlaybackControls.Listener extends android.media.session.RouteInterface.EventListener {
- ctor public RoutePlaybackControls.Listener();
- method public final void onEvent(java.lang.String, android.os.Bundle);
- method public void onMetadataUpdate(android.media.session.MediaMetadata);
- method public void onPlaybackStateChange(int);
- }
-
- public final class Session {
- method public void addCallback(android.media.session.Session.Callback);
- method public void addCallback(android.media.session.Session.Callback, android.os.Handler);
- method public void connect(android.media.session.RouteInfo, android.media.session.RouteOptions);
- method public void disconnect();
- method public android.media.session.SessionToken getSessionToken();
- method public android.media.session.TransportPerformer getTransportPerformer();
- method public boolean isActive();
- method public void release();
- method public void removeCallback(android.media.session.Session.Callback);
- method public void sendEvent(java.lang.String, android.os.Bundle);
- method public void setActive(boolean);
- method public void setFlags(int);
- method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
- field public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2; // 0x2
- field public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3; // 0x3
- field public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5; // 0x5
- field public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4; // 0x4
- field public static final int DISCONNECT_REASON_USER_STOPPING = 1; // 0x1
- field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
- field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
- }
-
- public static abstract class Session.Callback {
- ctor public Session.Callback();
- method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- method public void onMediaButton(android.content.Intent);
- method public void onRequestRouteChange(android.media.session.RouteInfo);
- method public void onRouteConnected(android.media.session.Route);
- method public void onRouteDisconnected(android.media.session.Route, int);
- }
-
- public final class SessionController {
- method public void addCallback(android.media.session.SessionController.Callback);
- method public void addCallback(android.media.session.SessionController.Callback, android.os.Handler);
- method public static android.media.session.SessionController fromToken(android.media.session.SessionToken);
- method public android.media.session.TransportController getTransportController();
- method public void removeCallback(android.media.session.SessionController.Callback);
- method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- method public void sendMediaButton(int);
- method public void showRoutePicker();
- }
-
- public static abstract class SessionController.Callback {
- ctor public SessionController.Callback();
- method public void onEvent(java.lang.String, android.os.Bundle);
- method public void onRouteChanged(android.media.session.RouteInfo);
- }
-
- public final class SessionInfo implements android.os.Parcelable {
- method public int describeContents();
- method public java.lang.String getId();
- method public java.lang.String getPackageName();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public final class SessionManager {
- method public android.media.session.Session createSession(java.lang.String);
- method public java.util.List<android.media.session.SessionController> getActiveSessions(android.content.ComponentName);
- }
-
- public class SessionToken implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
public final class TransportController {
method public void addStateListener(android.media.session.TransportController.TransportStateListener);
method public void addStateListener(android.media.session.TransportController.TransportStateListener, android.os.Handler);
method public void fastForward();
- method public android.media.session.MediaMetadata getMetadata();
+ method public android.media.MediaMetadata getMetadata();
method public android.media.session.PlaybackState getPlaybackState();
method public int getRatingType();
method public void next();
@@ -15657,7 +15499,7 @@
public static abstract class TransportController.TransportStateListener {
ctor public TransportController.TransportStateListener();
- method public void onMetadataChanged(android.media.session.MediaMetadata);
+ method public void onMetadataChanged(android.media.MediaMetadata);
method public void onPlaybackStateChanged(android.media.session.PlaybackState);
}
@@ -15665,7 +15507,7 @@
method public void addListener(android.media.session.TransportPerformer.Listener);
method public void addListener(android.media.session.TransportPerformer.Listener, android.os.Handler);
method public void removeListener(android.media.session.TransportPerformer.Listener);
- method public final void setMetadata(android.media.session.MediaMetadata);
+ method public final void setMetadata(android.media.MediaMetadata);
method public final void setPlaybackState(android.media.session.PlaybackState);
}
@@ -15818,18 +15660,23 @@
method public android.net.NetworkInfo getActiveNetworkInfo();
method public android.net.NetworkInfo[] getAllNetworkInfo();
method public deprecated boolean getBackgroundDataSetting();
- method public android.net.ProxyInfo getGlobalProxy();
+ method public android.net.LinkProperties getLinkProperties(android.net.Network);
+ method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
method public android.net.NetworkInfo getNetworkInfo(int);
- method public int getNetworkPreference();
+ method public deprecated int getNetworkPreference();
method public boolean isActiveNetworkMetered();
method public boolean isNetworkActive();
method public static boolean isNetworkTypeValid(int);
+ method public android.net.NetworkRequest listenForNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
- method public boolean requestRouteToHost(int, int);
- method public void setGlobalProxy(android.net.ProxyInfo);
- method public void setNetworkPreference(int);
- method public int startUsingNetworkFeature(int, java.lang.String);
- method public int stopUsingNetworkFeature(int, java.lang.String);
+ method public void releaseNetworkRequest(android.net.NetworkRequest);
+ method public void reportBadNetwork(android.net.Network);
+ method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
+ method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.app.PendingIntent);
+ method public deprecated boolean requestRouteToHost(int, int);
+ method public deprecated void setNetworkPreference(int);
+ method public deprecated int startUsingNetworkFeature(int, java.lang.String);
+ method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
method public void unregisterNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
@@ -15837,6 +15684,8 @@
field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
+ field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
+ field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES = "networkRequestNetworkCapabilities";
field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType";
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
@@ -15853,6 +15702,16 @@
field public static final int TYPE_WIMAX = 6; // 0x6
}
+ public static class ConnectivityManager.NetworkCallbackListener {
+ ctor public ConnectivityManager.NetworkCallbackListener();
+ method public void onAvailable(android.net.NetworkRequest, android.net.Network);
+ method public void onLinkPropertiesChanged(android.net.NetworkRequest, android.net.Network, android.net.LinkProperties);
+ method public void onLosing(android.net.NetworkRequest, android.net.Network, int);
+ method public void onLost(android.net.NetworkRequest, android.net.Network);
+ method public void onNetworkCapabilitiesChanged(android.net.NetworkRequest, android.net.Network, android.net.NetworkCapabilities);
+ method public void onReleased(android.net.NetworkRequest);
+ }
+
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
method public abstract void onNetworkActive();
}
@@ -15877,6 +15736,48 @@
field public int serverAddress;
}
+ public class LinkAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.net.InetAddress getAddress();
+ method public int getFlags();
+ method public int getNetworkPrefixLength();
+ method public int getScope();
+ method public boolean isSameAddressAs(android.net.LinkAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
+ public class LinkProperties implements android.os.Parcelable {
+ ctor public LinkProperties();
+ ctor public LinkProperties(android.net.LinkProperties);
+ method public void addDns(java.net.InetAddress);
+ method public boolean addLinkAddress(android.net.LinkAddress);
+ method public void addRoute(android.net.RouteInfo);
+ method public void clear();
+ method public int describeContents();
+ method public java.util.Collection<java.lang.String> getAllInterfaceNames();
+ method public java.util.Collection<java.net.InetAddress> getDnses();
+ method public java.lang.String getDomains();
+ method public android.net.ProxyInfo getHttpProxy();
+ method public java.lang.String getInterfaceName();
+ method public java.util.Collection<android.net.LinkAddress> getLinkAddresses();
+ method public java.util.Collection<android.net.RouteInfo> getRoutes();
+ method public boolean hasIPv4Address();
+ method public boolean hasIPv6Address();
+ method public boolean removeLinkAddress(android.net.LinkAddress);
+ method public void setDomains(java.lang.String);
+ method public void setHttpProxy(android.net.ProxyInfo);
+ method public void setInterfaceName(java.lang.String);
+ method public void setLinkAddresses(java.util.Collection<android.net.LinkAddress>);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static class LinkProperties.CompareResult {
+ ctor public LinkProperties.CompareResult();
+ field public java.util.Collection added;
+ field public java.util.Collection removed;
+ }
+
public class LocalServerSocket {
ctor public LocalServerSocket(java.lang.String) throws java.io.IOException;
ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -15945,6 +15846,56 @@
field public static final java.lang.String MAILTO_SCHEME = "mailto:";
}
+ public class Network implements android.os.Parcelable {
+ method public void bindProcess();
+ method public int describeContents();
+ method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
+ method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
+ method public static android.net.Network getProcessBoundNetwork();
+ method public javax.net.SocketFactory socketFactory();
+ method public static void unbindProcess();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ ctor public NetworkCapabilities();
+ ctor public NetworkCapabilities(android.net.NetworkCapabilities);
+ method public void addNetworkCapability(int);
+ method public void addTransportType(int);
+ method public int describeContents();
+ method public int getLinkDownstreamBandwidthKbps();
+ method public int getLinkUpstreamBandwidthKbps();
+ method public java.util.Collection<java.lang.Integer> getNetworkCapabilities();
+ method public java.util.Collection<java.lang.Integer> getTransportTypes();
+ method public boolean hasCapability(int);
+ method public boolean hasTransport(int);
+ method public void removeNetworkCapability(int);
+ method public void removeTransportType(int);
+ method public void setLinkDownstreamBandwidthKbps(int);
+ method public void setLinkUpstreamBandwidthKbps(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int NET_CAPABILITY_CBS = 5; // 0x5
+ field public static final int NET_CAPABILITY_DUN = 2; // 0x2
+ field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+ field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
+ field public static final int NET_CAPABILITY_IA = 7; // 0x7
+ field public static final int NET_CAPABILITY_IMS = 4; // 0x4
+ field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
+ field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+ field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
+ field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_RCS = 8; // 0x8
+ field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
+ field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
+ field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
+ field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
+ field public static final int TRANSPORT_CELLULAR = 0; // 0x0
+ field public static final int TRANSPORT_ETHERNET = 3; // 0x3
+ field public static final int TRANSPORT_WIFI = 1; // 0x1
+ }
+
public class NetworkInfo implements android.os.Parcelable {
method public int describeContents();
method public android.net.NetworkInfo.DetailedState getDetailedState();
@@ -15992,6 +15943,13 @@
enum_constant public static final android.net.NetworkInfo.State UNKNOWN;
}
+ public class NetworkRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public final android.net.NetworkCapabilities networkCapabilities;
+ }
+
public class ParseException extends java.lang.RuntimeException {
field public java.lang.String response;
}
@@ -16018,6 +15976,20 @@
method public void writeToParcel(android.os.Parcel, int);
}
+ public class RouteInfo implements android.os.Parcelable {
+ ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress, java.lang.String);
+ ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress);
+ ctor public RouteInfo(java.net.InetAddress);
+ ctor public RouteInfo(android.net.LinkAddress);
+ method public int describeContents();
+ method public android.net.LinkAddress getDestination();
+ method public java.net.InetAddress getGateway();
+ method public java.lang.String getInterface();
+ method public boolean isDefaultRoute();
+ method public boolean matches(java.net.InetAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
ctor public deprecated SSLCertificateSocketFactory(int);
method public java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
@@ -16854,6 +16826,86 @@
method public void setWorkSource(android.os.WorkSource);
}
+ public class WifiScanner {
+ method public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.HotspotInfo[]);
+ method public void resetHotlist(android.net.wifi.WifiScanner.HotlistListener);
+ method public void retrieveScanResults(boolean, android.net.wifi.WifiScanner.ScanListener);
+ method public void setHotlist(android.net.wifi.WifiScanner.HotspotInfo[], int, android.net.wifi.WifiScanner.HotlistListener);
+ method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+ method public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+ method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
+ method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+ field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
+ field public static final int MIN_SCAN_PERIOD_MS = 2000; // 0x7d0
+ field public static final int REASON_CONFLICTING_REQUEST = -4; // 0xfffffffc
+ field public static final int REASON_INVALID_LISTENER = -2; // 0xfffffffe
+ field public static final int REASON_INVALID_REQUEST = -3; // 0xfffffffd
+ field public static final int REASON_SUCCEEDED = 0; // 0x0
+ field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+ field public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
+ field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
+ field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
+ field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
+ field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
+ field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
+ field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
+ field public static final int WIFI_BAND_BOTH = 3; // 0x3
+ field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
+ field public static final int WIFI_BAND_UNSPECIFIED = 0; // 0x0
+ }
+
+ public static class WifiScanner.ChannelSpec {
+ ctor public WifiScanner.ChannelSpec(int);
+ field public int frequency;
+ }
+
+ public static class WifiScanner.FullScanResult implements android.os.Parcelable {
+ ctor public WifiScanner.FullScanResult();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public android.net.wifi.WifiScanner.InformationElement[] informationElements;
+ field public android.net.wifi.ScanResult result;
+ }
+
+ public static abstract interface WifiScanner.HotlistListener {
+ method public abstract void onFound(android.net.wifi.ScanResult[]);
+ }
+
+ public static class WifiScanner.HotspotInfo {
+ ctor public WifiScanner.HotspotInfo();
+ field public java.lang.String bssid;
+ field public int frequencyHint;
+ field public int high;
+ field public int low;
+ }
+
+ public static class WifiScanner.InformationElement {
+ ctor public WifiScanner.InformationElement();
+ field public byte[] bytes;
+ field public int id;
+ }
+
+ public static abstract interface WifiScanner.ScanListener {
+ method public abstract void onFullResult(android.net.wifi.WifiScanner.FullScanResult);
+ method public abstract void onPeriodChanged(int);
+ method public abstract void onResults(android.net.wifi.ScanResult[]);
+ }
+
+ public static class WifiScanner.ScanSettings implements android.os.Parcelable {
+ ctor public WifiScanner.ScanSettings();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public int band;
+ field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
+ field public int periodInMs;
+ field public int reportEvents;
+ }
+
+ public static abstract interface WifiScanner.WifiChangeListener {
+ method public abstract void onChanging(android.net.wifi.ScanResult[]);
+ method public abstract void onQuiescence(android.net.wifi.ScanResult[]);
+ }
+
public class WpsInfo implements android.os.Parcelable {
ctor public WpsInfo();
ctor public WpsInfo(android.net.wifi.WpsInfo);
@@ -16871,19 +16923,6 @@
}
-package android.net.wifi.hotspot {
-
- public abstract interface IWifiHotspotManager implements android.os.IInterface {
- method public abstract void test() throws android.os.RemoteException;
- }
-
- public class WifiHotspotManager {
- ctor public WifiHotspotManager(android.content.Context, android.net.wifi.hotspot.IWifiHotspotManager);
- method public void test();
- }
-
-}
-
package android.net.wifi.p2p {
public class WifiP2pConfig implements android.os.Parcelable {
@@ -17079,6 +17118,114 @@
}
+package android.net.wifi.passpoint {
+
+ public abstract interface IPasspointManager implements android.os.IInterface {
+ method public abstract android.os.Messenger getMessenger() throws android.os.RemoteException;
+ method public abstract int getPasspointState() throws android.os.RemoteException;
+ }
+
+ public class PasspointCredential implements android.os.Parcelable {
+ ctor public PasspointCredential();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
+ public class PasspointInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ANQP_CAPABILITY = 1; // 0x1
+ field public static final int CELLULAR_NETWORK = 64; // 0x40
+ field public static final int CONNECTION_CAPABILITY = 2048; // 0x800
+ field public static final int DOMAIN_NAME = 128; // 0x80
+ field public static final int HOTSPOT_CAPABILITY = 256; // 0x100
+ field public static final int IP_ADDR_TYPE_AVAILABILITY = 16; // 0x10
+ field public static final int NAI_REALM = 32; // 0x20
+ field public static final int NETWORK_AUTH_TYPE = 4; // 0x4
+ field public static final int OPERATOR_FRIENDLY_NAME = 512; // 0x200
+ field public static final int OSU_PROVIDER = 4096; // 0x1000
+ field public static final int PRESET_ALL = 8191; // 0x1fff
+ field public static final int PRESET_CRED_MATCH = 481; // 0x1e1
+ field public static final int ROAMING_CONSORTIUM = 8; // 0x8
+ field public static final int VENUE_NAME = 2; // 0x2
+ field public static final int WAN_METRICS = 1024; // 0x400
+ field public java.lang.String bssid;
+ field public java.lang.String cellularNetwork;
+ field public java.lang.String connectionCapability;
+ field public java.lang.String domainName;
+ field public java.lang.String ipAddrTypeAvaibility;
+ field public java.lang.String naiRealm;
+ field public java.lang.String networkAuthType;
+ field public java.lang.String operatorFriendlyName;
+ field public java.util.List osuProviderList;
+ field public java.lang.String roamingConsortium;
+ field public java.lang.String venueName;
+ field public java.lang.String wanMetrics;
+ }
+
+ public class PasspointManager {
+ ctor public PasspointManager(android.content.Context, android.net.wifi.passpoint.IPasspointManager);
+ method public boolean addCredential(android.net.wifi.passpoint.PasspointCredential);
+ method public void connect(android.net.wifi.passpoint.PasspointPolicy);
+ method public int getPasspointState();
+ method public java.util.List<android.net.wifi.passpoint.PasspointCredential> getSavedCredentials();
+ method public android.net.wifi.passpoint.PasspointManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.passpoint.PasspointManager.ChannelListener);
+ method public boolean removeCredential(android.net.wifi.passpoint.PasspointCredential);
+ method public java.util.List<android.net.wifi.passpoint.PasspointPolicy> requestCredentialMatch(java.util.List<android.net.wifi.ScanResult>);
+ method public void requestOsuIcons(android.net.wifi.passpoint.PasspointManager.Channel, java.util.List<android.net.wifi.passpoint.PasspointOsuProvider>, int, android.net.wifi.passpoint.PasspointManager.ActionListener);
+ method public boolean updateCredential(android.net.wifi.passpoint.PasspointCredential);
+ field public static final int BUSY = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final java.lang.String PASSPOINT_CRED_CHANGED_ACTION = "android.net.wifi.passpoint.CRED_CHANGE";
+ field public static final int PASSPOINT_STATE_ACCESS = 3; // 0x3
+ field public static final java.lang.String PASSPOINT_STATE_CHANGED_ACTION = "android.net.wifi.passpoint.STATE_CHANGE";
+ field public static final int PASSPOINT_STATE_DISABLED = 1; // 0x1
+ field public static final int PASSPOINT_STATE_DISCOVERY = 2; // 0x2
+ field public static final int PASSPOINT_STATE_PROVISION = 4; // 0x4
+ field public static final int PASSPOINT_STATE_UNKNOWN = 0; // 0x0
+ field public static final int WIFI_DISABLED = 1; // 0x1
+ }
+
+ public static abstract interface PasspointManager.ActionListener {
+ method public abstract void onFailure(int);
+ method public abstract void onSuccess();
+ }
+
+ public static class PasspointManager.Channel {
+ }
+
+ public static abstract interface PasspointManager.ChannelListener {
+ method public abstract void onChannelDisconnected();
+ }
+
+ public class PasspointOsuProvider implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int OSU_METHOD_OMADM = 0; // 0x0
+ field public static final int OSU_METHOD_SOAP = 1; // 0x1
+ field public static final int OSU_METHOD_UNKNOWN = -1; // 0xffffffff
+ field public java.lang.String friendlyName;
+ field public java.lang.Object icon;
+ field public java.lang.String iconFileName;
+ field public int iconHeight;
+ field public java.lang.String iconType;
+ field public int iconWidth;
+ field public int osuMethod;
+ field public java.lang.String osuNai;
+ field public java.lang.String osuService;
+ field public java.lang.String serverUri;
+ field public java.lang.String ssid;
+ }
+
+ public class PasspointPolicy implements android.os.Parcelable {
+ ctor public PasspointPolicy();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
+}
+
package android.nfc {
public class FormatException extends java.lang.Exception {
@@ -25337,72 +25484,6 @@
}
-package android.service.voice {
-
- public class VoiceInteractionService extends android.app.Service {
- ctor public VoiceInteractionService();
- method public android.os.IBinder onBind(android.content.Intent);
- method public void startSession(android.os.Bundle);
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
- field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
- }
-
- public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
- ctor public VoiceInteractionSession(android.content.Context);
- ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
- method public void finish();
- method public android.view.LayoutInflater getLayoutInflater();
- method public android.app.Dialog getWindow();
- method public void hideWindow();
- method public void onBackPressed();
- method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
- method public void onCloseSystemDialogs();
- method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
- method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
- method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
- method public void onCreate(android.os.Bundle);
- method public android.view.View onCreateContentView();
- method public void onDestroy();
- method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
- method public boolean onKeyDown(int, android.view.KeyEvent);
- method public boolean onKeyLongPress(int, android.view.KeyEvent);
- method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
- method public boolean onKeyUp(int, android.view.KeyEvent);
- method public void onTaskFinished(android.content.Intent, int);
- method public void onTaskStarted(android.content.Intent, int);
- method public void setContentView(android.view.View);
- method public void setTheme(int);
- method public void showWindow();
- method public void startVoiceActivity(android.content.Intent);
- }
-
- public static class VoiceInteractionSession.Caller {
- }
-
- public static final class VoiceInteractionSession.Insets {
- ctor public VoiceInteractionSession.Insets();
- field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
- field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
- field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
- field public int contentTopInsets;
- field public int touchableInsets;
- field public final android.graphics.Region touchableRegion;
- }
-
- public static class VoiceInteractionSession.Request {
- method public void sendCancelResult();
- method public void sendCommandResult(boolean, android.os.Bundle);
- method public void sendConfirmResult(boolean, android.os.Bundle);
- }
-
- public abstract class VoiceInteractionSessionService extends android.app.Service {
- ctor public VoiceInteractionSessionService();
- method public android.os.IBinder onBind(android.content.Intent);
- method public abstract android.service.voice.VoiceInteractionSession onNewSession(android.os.Bundle);
- }
-
-}
-
package android.service.wallpaper {
public abstract class WallpaperService extends android.app.Service {
@@ -26607,6 +26688,83 @@
enum_constant public static final android.telecomm.CallState RINGING;
}
+ public abstract class Connection {
+ ctor protected Connection();
+ method public final android.telecomm.CallAudioState getCallAudioState();
+ method public final android.net.Uri getHandle();
+ method protected void onAbort();
+ method protected void onAnswer();
+ method protected void onDisconnect();
+ method protected void onHold();
+ method protected void onPlayDtmfTone(char);
+ method protected void onReject();
+ method protected void onSetAudioState(android.telecomm.CallAudioState);
+ method protected void onSetSignal(android.os.Bundle);
+ method protected void onStopDtmfTone();
+ method protected void onUnhold();
+ method protected void setActive();
+ method public void setAudioState(android.telecomm.CallAudioState);
+ method protected void setDialing();
+ method protected void setDisconnected(int, java.lang.String);
+ method protected void setHandle(android.net.Uri);
+ method protected void setOnHold();
+ method protected void setRinging();
+ method public static java.lang.String stateToString(int);
+ }
+
+ public static abstract interface Connection.Listener {
+ method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+ method public abstract void onDestroyed(android.telecomm.Connection);
+ method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
+ method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+ method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
+ method public abstract void onStateChanged(android.telecomm.Connection, int);
+ }
+
+ public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
+ ctor public Connection.ListenerBase();
+ method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+ method public void onDestroyed(android.telecomm.Connection);
+ method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
+ method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+ method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
+ method public void onStateChanged(android.telecomm.Connection, int);
+ }
+
+ public final class Connection.State {
+ field public static final int ACTIVE = 3; // 0x3
+ field public static final int DIALING = 2; // 0x2
+ field public static final int DISCONNECTED = 5; // 0x5
+ field public static final int HOLDING = 4; // 0x4
+ field public static final int NEW = 0; // 0x0
+ field public static final int RINGING = 1; // 0x1
+ }
+
+ public final class ConnectionRequest {
+ ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
+ method public android.os.Bundle getExtras();
+ method public android.net.Uri getHandle();
+ }
+
+ public abstract class ConnectionService extends android.telecomm.CallService {
+ ctor public ConnectionService();
+ method public final void abort(java.lang.String);
+ method public final void answer(java.lang.String);
+ method public final void call(android.telecomm.CallInfo);
+ method public final void disconnect(java.lang.String);
+ method public final void hold(java.lang.String);
+ method public final void isCompatibleWith(android.telecomm.CallInfo);
+ method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+ method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
+ method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
+ method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
+ method public final void playDtmfTone(java.lang.String, char);
+ method public final void reject(java.lang.String);
+ method public final void setIncomingCallId(java.lang.String, android.os.Bundle);
+ method public final void stopDtmfTone(java.lang.String);
+ method public final void unhold(java.lang.String);
+ }
+
public class GatewayInfo implements android.os.Parcelable {
method public int describeContents();
method public android.net.Uri getGatewayHandle();
@@ -26658,6 +26816,18 @@
method protected abstract void updateCall(android.telecomm.InCallCall);
}
+ public abstract interface Response {
+ method public abstract void onError(IN, java.lang.String);
+ method public abstract void onResult(IN, OUT...);
+ }
+
+ public class Subscription implements android.os.Parcelable {
+ ctor public Subscription();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public final class TelecommConstants {
ctor public TelecommConstants();
field public static final java.lang.String ACTION_CALL_SERVICE;
@@ -27114,6 +27284,7 @@
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
method public boolean isNetworkRoaming();
method public void listen(android.telephony.PhoneStateListener, int);
+ method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
field public static final int CALL_STATE_IDLE = 0; // 0x0
@@ -29986,6 +30157,12 @@
method public T getUpper();
}
+ public final class Rational {
+ ctor public Rational(int, int);
+ method public int getDenominator();
+ method public int getNumerator();
+ }
+
public final class Size {
ctor public Size(int, int);
method public int getHeight();
@@ -30824,6 +31001,7 @@
field public static final int KEYCODE_P = 44; // 0x2c
field public static final int KEYCODE_PAGE_DOWN = 93; // 0x5d
field public static final int KEYCODE_PAGE_UP = 92; // 0x5c
+ field public static final int KEYCODE_PAIRING = 225; // 0xe1
field public static final int KEYCODE_PERIOD = 56; // 0x38
field public static final int KEYCODE_PICTSYMBOLS = 94; // 0x5e
field public static final int KEYCODE_PLUS = 81; // 0x51
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 36c36a8..e1a94d7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1222,6 +1222,7 @@
* Check whether this activity is running as part of a voice interaction with the user.
* If true, it should perform its interaction with the user through the
* {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
+ * @hide
*/
public boolean isVoiceInteraction() {
return mVoiceInteractor != null;
@@ -1230,6 +1231,7 @@
/**
* Retrieve the active {@link VoiceInteractor} that the user is going through to
* interact with this activity.
+ * @hide
*/
public VoiceInteractor getVoiceInteractor() {
return mVoiceInteractor;
@@ -3611,15 +3613,15 @@
theme.applyStyle(resid, false);
}
- // Get the primary color and update the RecentsActivityValues for this activity
+ // Get the primary color and update the TaskDescription for this activity
if (theme != null) {
TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
a.recycle();
if (colorPrimary != 0) {
- ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
- v.colorPrimary = colorPrimary;
- setRecentsActivityValues(v);
+ ActivityManager.TaskDescription v = new ActivityManager.TaskDescription(null, null,
+ colorPrimary);
+ setTaskDescription(v);
}
}
}
@@ -4924,27 +4926,30 @@
}
/**
- * Sets information describing this Activity for presentation inside the Recents System UI. When
- * {@link ActivityManager#getRecentTasks} is called, the activities of each task are
- * traversed in order from the topmost activity to the bottommost. The traversal continues for
- * each property until a suitable value is found. For each task those values will be returned in
- * {@link android.app.ActivityManager.RecentsActivityValues}.
+ * Sets information describing the task with this activity for presentation inside the Recents
+ * System UI. When {@link ActivityManager#getRecentTasks} is called, the activities of each task
+ * are traversed in order from the topmost activity to the bottommost. The traversal continues
+ * for each property until a suitable value is found. For each task the taskDescription will be
+ * returned in {@link android.app.ActivityManager.TaskDescription}.
*
* @see ActivityManager#getRecentTasks
- * @see android.app.ActivityManager.RecentsActivityValues
+ * @see android.app.ActivityManager.TaskDescription
*
- * @param values The Recents values that describe this activity.
+ * @param taskDescription The TaskDescription properties that describe the task with this activity
*/
- public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
- ActivityManager.RecentsActivityValues activityValues =
- new ActivityManager.RecentsActivityValues(values);
- // Scale the icon down to something reasonable
- if (values.icon != null) {
+ public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
+ ActivityManager.TaskDescription td;
+ // Scale the icon down to something reasonable if it is provided
+ if (taskDescription.getIcon() != null) {
final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
- activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
+ final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true);
+ td = new ActivityManager.TaskDescription(taskDescription.getLabel(), icon,
+ taskDescription.getPrimaryColor());
+ } else {
+ td = taskDescription;
}
try {
- ActivityManagerNative.getDefault().setRecentsActivityValues(mToken, activityValues);
+ ActivityManagerNative.getDefault().setTaskDescription(mToken, td);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1d05320..abcb0d0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -33,6 +33,7 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Debug;
@@ -477,65 +478,84 @@
/**
* Information you can set and retrieve about the current activity within the recent task list.
*/
- public static class RecentsActivityValues implements Parcelable {
- public CharSequence label;
- public Bitmap icon;
- public int colorPrimary;
-
- public RecentsActivityValues(RecentsActivityValues values) {
- copyFrom(values);
- }
+ public static class TaskDescription implements Parcelable {
+ private String mLabel;
+ private Bitmap mIcon;
+ private int mColorPrimary;
/**
- * Creates the RecentsActivityValues to the specified values.
+ * Creates the TaskDescription to the specified values.
*
- * @param label A label and description of the current state of this activity.
- * @param icon An icon that represents the current state of this activity.
- * @param color A color to override the theme's primary color.
+ * @param label A label and description of the current state of this task.
+ * @param icon An icon that represents the current state of this task.
+ * @param colorPrimary A color to override the theme's primary color. This color must be opaque.
*/
- public RecentsActivityValues(CharSequence label, Bitmap icon, int color) {
- this.label = label;
- this.icon = icon;
- this.colorPrimary = color;
+ public TaskDescription(String label, Bitmap icon, int colorPrimary) {
+ if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
+ throw new RuntimeException("A TaskDescription's primary color should be opaque");
+ }
+
+ mLabel = label;
+ mIcon = icon;
+ mColorPrimary = colorPrimary;
}
/**
- * Creates the RecentsActivityValues to the specified values.
+ * Creates the TaskDescription to the specified values.
*
* @param label A label and description of the current state of this activity.
* @param icon An icon that represents the current state of this activity.
*/
- public RecentsActivityValues(CharSequence label, Bitmap icon) {
+ public TaskDescription(String label, Bitmap icon) {
this(label, icon, 0);
}
/**
- * Creates the RecentsActivityValues to the specified values.
+ * Creates the TaskDescription to the specified values.
*
* @param label A label and description of the current state of this activity.
*/
- public RecentsActivityValues(CharSequence label) {
+ public TaskDescription(String label) {
this(label, null, 0);
}
- public RecentsActivityValues() {
+ /**
+ * Creates an empty TaskDescription.
+ */
+ public TaskDescription() {
this(null, null, 0);
}
- private RecentsActivityValues(Parcel source) {
+ /**
+ * Creates a copy of another TaskDescription.
+ */
+ public TaskDescription(TaskDescription td) {
+ this(td.getLabel(), td.getIcon(), td.getPrimaryColor());
+ }
+
+ private TaskDescription(Parcel source) {
readFromParcel(source);
}
/**
- * Do a shallow copy of another set of activity values.
- * @hide
+ * @return The label and description of the current state of this task.
*/
- public void copyFrom(RecentsActivityValues v) {
- if (v != null) {
- label = v.label;
- icon = v.icon;
- colorPrimary = v.colorPrimary;
- }
+ public String getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * @return The icon that represents the current state of this task.
+ */
+ public Bitmap getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * @return The color override on the theme's primary color.
+ */
+ public int getPrimaryColor() {
+ return mColorPrimary;
}
@Override
@@ -545,37 +565,41 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- TextUtils.writeToParcel(label, dest,
- Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
- if (icon == null) {
+ if (mLabel == null) {
dest.writeInt(0);
} else {
dest.writeInt(1);
- icon.writeToParcel(dest, 0);
+ dest.writeString(mLabel);
}
- dest.writeInt(colorPrimary);
+ if (mIcon == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ mIcon.writeToParcel(dest, 0);
+ }
+ dest.writeInt(mColorPrimary);
}
public void readFromParcel(Parcel source) {
- label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- icon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
- colorPrimary = source.readInt();
+ mLabel = source.readInt() > 0 ? source.readString() : null;
+ mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+ mColorPrimary = source.readInt();
}
- public static final Creator<RecentsActivityValues> CREATOR
- = new Creator<RecentsActivityValues>() {
- public RecentsActivityValues createFromParcel(Parcel source) {
- return new RecentsActivityValues(source);
+ public static final Creator<TaskDescription> CREATOR
+ = new Creator<TaskDescription>() {
+ public TaskDescription createFromParcel(Parcel source) {
+ return new TaskDescription(source);
}
- public RecentsActivityValues[] newArray(int size) {
- return new RecentsActivityValues[size];
+ public TaskDescription[] newArray(int size) {
+ return new TaskDescription[size];
}
};
@Override
public String toString() {
- return "RecentsActivityValues Label: " + label + " Icon: " + icon +
- " colorPrimary: " + colorPrimary;
+ return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
+ " colorPrimary: " + mColorPrimary;
}
}
@@ -629,9 +653,11 @@
/**
* The recent activity values for the highest activity in the stack to have set the values.
- * {@link Activity#setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues)}.
+ * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
+ *
+ * @hide
*/
- public RecentsActivityValues activityValues;
+ public TaskDescription taskDescription;
public RecentTaskInfo() {
}
@@ -654,9 +680,9 @@
ComponentName.writeToParcel(origActivity, dest);
TextUtils.writeToParcel(description, dest,
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
- if (activityValues != null) {
+ if (taskDescription != null) {
dest.writeInt(1);
- activityValues.writeToParcel(dest, 0);
+ taskDescription.writeToParcel(dest, 0);
} else {
dest.writeInt(0);
}
@@ -670,8 +696,8 @@
baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
origActivity = ComponentName.readFromParcel(source);
description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- activityValues = source.readInt() > 0 ?
- RecentsActivityValues.CREATOR.createFromParcel(source) : null;
+ taskDescription = source.readInt() > 0 ?
+ TaskDescription.CREATOR.createFromParcel(source) : null;
stackId = source.readInt();
userId = source.readInt();
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e704a1c..0f65454 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2158,12 +2158,12 @@
return true;
}
- case SET_RECENTS_ACTIVITY_VALUES_TRANSACTION: {
+ case SET_TASK_DESCRIPTION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- ActivityManager.RecentsActivityValues values =
- ActivityManager.RecentsActivityValues.CREATOR.createFromParcel(data);
- setRecentsActivityValues(token, values);
+ ActivityManager.TaskDescription values =
+ ActivityManager.TaskDescription.CREATOR.createFromParcel(data);
+ setTaskDescription(token, values);
reply.writeNoException();
return true;
}
@@ -4967,14 +4967,14 @@
}
@Override
- public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+ public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
values.writeToParcel(data, 0);
- mRemote.transact(SET_RECENTS_ACTIVITY_VALUES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+ mRemote.transact(SET_TASK_DESCRIPTION_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 71e4e82..5fd288f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3010,19 +3010,10 @@
int h;
if (w < 0) {
Resources res = r.activity.getResources();
- Configuration config = res.getConfiguration();
- boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
- if (useAlternateRecents) {
- int wId = com.android.internal.R.dimen.recents_thumbnail_width;
- int hId = com.android.internal.R.dimen.recents_thumbnail_height;
- mThumbnailWidth = w = res.getDimensionPixelSize(wId);
- mThumbnailHeight = h = res.getDimensionPixelSize(hId);
- } else {
- mThumbnailHeight = h =
- res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
- mThumbnailWidth = w =
- res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
- }
+ int wId = com.android.internal.R.dimen.recents_thumbnail_width;
+ int hId = com.android.internal.R.dimen.recents_thumbnail_height;
+ mThumbnailWidth = w = res.getDimensionPixelSize(wId);
+ mThumbnailHeight = h = res.getDimensionPixelSize(hId);
} else {
h = mThumbnailHeight;
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d813dab..62c4f0f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.os.Binder;
import android.os.IBinder;
+import android.os.UserManager;
import android.util.ArrayMap;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsCallback;
@@ -412,6 +413,58 @@
};
/**
+ * Specifies whether an Op should be restricted by a user restriction.
+ * Each Op should be filled with a restriction string from UserManager or
+ * null to specify it is not affected by any user restriction.
+ */
+ private static String[] sOpRestrictions = new String[] {
+ null, //COARSE_LOCATION
+ null, //FINE_LOCATION
+ null, //GPS
+ null, //VIBRATE
+ null, //READ_CONTACTS
+ null, //WRITE_CONTACTS
+ null, //READ_CALL_LOG
+ null, //WRITE_CALL_LOG
+ null, //READ_CALENDAR
+ null, //WRITE_CALENDAR
+ null, //WIFI_SCAN
+ null, //POST_NOTIFICATION
+ null, //NEIGHBORING_CELLS
+ null, //CALL_PHONE
+ null, //READ_SMS
+ null, //WRITE_SMS
+ null, //RECEIVE_SMS
+ null, //RECEIVE_EMERGECY_SMS
+ null, //RECEIVE_MMS
+ null, //RECEIVE_WAP_PUSH
+ null, //SEND_SMS
+ null, //READ_ICC_SMS
+ null, //WRITE_ICC_SMS
+ null, //WRITE_SETTINGS
+ null, //SYSTEM_ALERT_WINDOW
+ null, //ACCESS_NOTIFICATIONS
+ null, //CAMERA
+ null, //RECORD_AUDIO
+ null, //PLAY_AUDIO
+ null, //READ_CLIPBOARD
+ null, //WRITE_CLIPBOARD
+ null, //TAKE_MEDIA_BUTTONS
+ null, //TAKE_AUDIO_FOCUS
+ null, //AUDIO_MASTER_VOLUME
+ null, //AUDIO_VOICE_VOLUME
+ null, //AUDIO_RING_VOLUME
+ null, //AUDIO_MEDIA_VOLUME
+ null, //AUDIO_ALARM_VOLUME
+ null, //AUDIO_NOTIFICATION_VOLUME
+ null, //AUDIO_BLUETOOTH_VOLUME
+ null, //WAKE_LOCK
+ null, //MONITOR_LOCATION
+ null, //MONITOR_HIGH_POWER_LOCATION
+ null, //GET_USAGE_STATS
+ };
+
+ /**
* This specifies the default mode for each operation.
*/
private static int[] sOpDefaultMode = new int[] {
@@ -542,6 +595,10 @@
throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
+ " should be " + _NUM_OP);
}
+ if (sOpRestrictions.length != _NUM_OP) {
+ throw new IllegalStateException("sOpRestrictions length " + sOpRestrictions.length
+ + " should be " + _NUM_OP);
+ }
for (int i=0; i<_NUM_OP; i++) {
if (sOpToString[i] != null) {
sOpStrToOp.put(sOpToString[i], i);
@@ -575,6 +632,14 @@
}
/**
+ * Retrieve the user restriction associated with an operation, or null if there is not one.
+ * @hide
+ */
+ public static String opToRestriction(int op) {
+ return sOpRestrictions[op];
+ }
+
+ /**
* Retrieve the default mode for the operation.
* @hide
*/
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b4d8942..6324d4c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -70,7 +70,7 @@
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaRouter;
-import android.media.session.SessionManager;
+import android.media.session.MediaSessionManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.INetworkPolicyManager;
@@ -81,8 +81,8 @@
import android.net.nsd.NsdManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
-import android.net.wifi.hotspot.IWifiHotspotManager;
-import android.net.wifi.hotspot.WifiHotspotManager;
+import android.net.wifi.passpoint.IPasspointManager;
+import android.net.wifi.passpoint.PasspointManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager;
import android.nfc.NfcManager;
@@ -578,11 +578,11 @@
return new WifiManager(ctx.getOuterContext(), service);
}});
- registerService(WIFI_HOTSPOT_SERVICE, new ServiceFetcher() {
+ registerService(WIFI_PASSPOINT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(WIFI_HOTSPOT_SERVICE);
- IWifiHotspotManager service = IWifiHotspotManager.Stub.asInterface(b);
- return new WifiHotspotManager(ctx.getOuterContext(), service);
+ IBinder b = ServiceManager.getService(WIFI_PASSPOINT_SERVICE);
+ IPasspointManager service = IPasspointManager.Stub.asInterface(b);
+ return new PasspointManager(ctx.getOuterContext(), service);
}});
registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
@@ -657,7 +657,7 @@
registerService(MEDIA_SESSION_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
- return new SessionManager(ctx);
+ return new MediaSessionManager(ctx);
}
});
registerService(TRUST_SERVICE, new ServiceFetcher() {
@@ -1345,6 +1345,15 @@
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
int initialCode, String initialData, Bundle initialExtras) {
+ sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE,
+ resultReceiver, scheduler, initialCode, initialData, initialExtras);
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ Handler scheduler,
+ int initialCode, String initialData, Bundle initialExtras) {
IIntentReceiver rd = null;
if (resultReceiver != null) {
if (mPackageInfo != null) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8753312..8434c2a0 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -440,7 +440,7 @@
public boolean isInLockTaskMode() throws RemoteException;
/** @hide */
- public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+ public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException;
/*
@@ -739,7 +739,7 @@
int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
- int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+ int SET_TASK_DESCRIPTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 76a6a8e..fd76b9c4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,9 +16,6 @@
package android.app;
-import com.android.internal.R;
-import com.android.internal.util.NotificationColorUtil;
-
import android.annotation.IntDef;
import android.content.Context;
import android.content.Intent;
@@ -41,6 +38,9 @@
import android.widget.ProgressBar;
import android.widget.RemoteViews;
+import com.android.internal.R;
+import com.android.internal.util.NotificationColorUtil;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.NumberFormat;
@@ -134,7 +134,7 @@
* leave it at its default value of 0.
*
* @see android.widget.ImageView#setImageLevel
- * @see android.graphics.drawable#setLevel
+ * @see android.graphics.drawable.Drawable#setLevel
*/
public int iconLevel;
@@ -700,10 +700,13 @@
* It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
* selected by the user.
* <p>
- * Apps should use {@link Builder#addAction(int, CharSequence, PendingIntent)} to create and
- * attach actions.
+ * Apps should use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}
+ * or {@link Notification.Builder#addAction(Notification.Action)}
+ * to attach actions.
*/
public static class Action implements Parcelable {
+ private final Bundle mExtras;
+
/**
* Small icon representing the action.
*/
@@ -717,22 +720,102 @@
* may be rendered in a disabled presentation by the system UI.
*/
public PendingIntent actionIntent;
-
- private Action() { }
+
private Action(Parcel in) {
icon = in.readInt();
title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
if (in.readInt() == 1) {
actionIntent = PendingIntent.CREATOR.createFromParcel(in);
}
+ mExtras = in.readBundle();
}
/**
- * Use {@link Builder#addAction(int, CharSequence, PendingIntent)}.
+ * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}.
*/
public Action(int icon, CharSequence title, PendingIntent intent) {
+ this(icon, title, intent, new Bundle());
+ }
+
+ private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
this.icon = icon;
this.title = title;
this.actionIntent = intent;
+ this.mExtras = extras != null ? extras : new Bundle();
+ }
+
+ /**
+ * Get additional metadata carried around with this Action.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Builder class for {@link Action} objects.
+ */
+ public static class Builder {
+ private final int mIcon;
+ private final CharSequence mTitle;
+ private final PendingIntent mIntent;
+ private final Bundle mExtras;
+
+ /**
+ * Construct a new builder for {@link Action} object.
+ * @param icon icon to show for this action
+ * @param title the title of the action
+ * @param intent the {@link PendingIntent} to fire when users trigger this action
+ */
+ public Builder(int icon, CharSequence title, PendingIntent intent) {
+ this(icon, title, intent, new Bundle());
+ }
+
+ /**
+ * Construct a new builder for {@link Action} object using the fields from an
+ * {@link Action}.
+ * @param action the action to read fields from.
+ */
+ public Builder(Action action) {
+ this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras));
+ }
+
+ private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
+ mIcon = icon;
+ mTitle = title;
+ mIntent = intent;
+ mExtras = extras;
+ }
+
+ /**
+ * Merge additional metadata into this builder.
+ *
+ * <p>Values within the Bundle will replace existing extras values in this Builder.
+ *
+ * @see Notification.Action#extras
+ */
+ public Builder addExtras(Bundle extras) {
+ if (extras != null) {
+ mExtras.putAll(extras);
+ }
+ return this;
+ }
+
+ /**
+ * Get the metadata Bundle used by this Builder.
+ *
+ * <p>The returned Bundle is shared with this Builder.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Combine all of the options that have been set and return a new {@link Action}
+ * object.
+ * @return the built action
+ */
+ public Action build() {
+ return new Action(mIcon, mTitle, mIntent, mExtras);
+ }
}
@Override
@@ -740,8 +823,8 @@
return new Action(
this.icon,
this.title,
- this.actionIntent // safe to alias
- );
+ this.actionIntent, // safe to alias
+ new Bundle(this.mExtras));
}
@Override
public int describeContents() {
@@ -757,9 +840,10 @@
} else {
out.writeInt(0);
}
+ out.writeBundle(mExtras);
}
- public static final Parcelable.Creator<Action> CREATOR
- = new Parcelable.Creator<Action>() {
+ public static final Parcelable.Creator<Action> CREATOR =
+ new Parcelable.Creator<Action>() {
public Action createFromParcel(Parcel in) {
return new Action(in);
}
@@ -1372,7 +1456,7 @@
/**
* Add a timestamp pertaining to the notification (usually the time the event occurred).
* It will be shown in the notification content view by default; use
- * {@link Builder#setShowWhen(boolean) setShowWhen} to control this.
+ * {@link #setShowWhen(boolean) setShowWhen} to control this.
*
* @see Notification#when
*/
@@ -1382,7 +1466,7 @@
}
/**
- * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown
+ * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown
* in the content view.
*/
public Builder setShowWhen(boolean show) {
@@ -1761,11 +1845,13 @@
*
* @see Notification#extras
*/
- public Builder addExtras(Bundle bag) {
- if (mExtras == null) {
- mExtras = new Bundle(bag);
- } else {
- mExtras.putAll(bag);
+ public Builder addExtras(Bundle extras) {
+ if (extras != null) {
+ if (mExtras == null) {
+ mExtras = new Bundle(extras);
+ } else {
+ mExtras.putAll(extras);
+ }
}
return this;
}
@@ -1782,8 +1868,8 @@
*
* @see Notification#extras
*/
- public Builder setExtras(Bundle bag) {
- mExtras = bag;
+ public Builder setExtras(Bundle extras) {
+ mExtras = extras;
return this;
}
@@ -1827,6 +1913,26 @@
}
/**
+ * Add an action to this notification. Actions are typically displayed by
+ * the system as a button adjacent to the notification content.
+ * <p>
+ * Every action must have an icon (32dp square and matching the
+ * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
+ * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
+ * <p>
+ * A notification in its expanded form can display up to 3 actions, from left to right in
+ * the order they were added. Actions will not be displayed when the notification is
+ * collapsed, however, so be sure that any essential functions may be accessed by the user
+ * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
+ *
+ * @param action The action to add.
+ */
+ public Builder addAction(Action action) {
+ mActions.add(action);
+ return this;
+ }
+
+ /**
* Add a rich notification style to be applied at build time.
*
* @param style Object responsible for modifying the notification style.
@@ -1889,26 +1995,20 @@
RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
boolean showLine3 = false;
boolean showLine2 = false;
- int smallIconImageViewId = R.id.icon;
+
if (mPriority < PRIORITY_LOW) {
// TODO: Low priority presentation
}
if (mLargeIcon != null) {
contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
processLargeIcon(mLargeIcon, contentView);
- smallIconImageViewId = R.id.right_icon;
- }
- if (mSmallIcon != 0) {
- contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
- contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
- if (mLargeIcon != null) {
- processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView);
- } else {
- processSmallIconAsLarge(mSmallIcon, contentView);
- }
-
- } else {
- contentView.setViewVisibility(smallIconImageViewId, View.GONE);
+ contentView.setImageViewResource(R.id.right_icon, mSmallIcon);
+ contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
+ processSmallRightIcon(mSmallIcon, contentView);
+ } else { // small icon at left
+ contentView.setImageViewResource(R.id.icon, mSmallIcon);
+ contentView.setViewVisibility(R.id.icon, View.VISIBLE);
+ processSmallIconAsLarge(mSmallIcon, contentView);
}
if (mContentTitle != null) {
contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle));
@@ -2103,6 +2203,8 @@
private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) {
applyLargeIconBackground(contentView);
+ } else {
+ removeLargeIconBackground(contentView);
}
}
@@ -2122,16 +2224,31 @@
-1);
}
+ private void removeLargeIconBackground(RemoteViews contentView) {
+ contentView.setInt(R.id.icon, "setBackgroundResource", 0);
+ }
+
/**
* Recolor small icons when used in the R.id.right_icon slot.
*/
- private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId,
+ private void processSmallRightIcon(int smallIconDrawableId,
RemoteViews contentView) {
if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
- contentView.setDrawableParameters(smallIconImageViewId, false, -1,
- mContext.getResources().getColor(
- R.color.notification_action_legacy_color_filter),
- PorterDuff.Mode.MULTIPLY, -1);
+ contentView.setDrawableParameters(R.id.right_icon, false, -1,
+ 0xFFFFFFFF,
+ PorterDuff.Mode.SRC_ATOP, -1);
+
+ contentView.setInt(R.id.right_icon,
+ "setBackgroundResource",
+ R.drawable.notification_icon_legacy_bg);
+
+ contentView.setDrawableParameters(
+ R.id.right_icon,
+ true,
+ -1,
+ mColor,
+ PorterDuff.Mode.SRC_ATOP,
+ -1);
}
}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 6dc48b0..4fcf7cd 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -34,6 +34,7 @@
/**
* Interface for an {@link Activity} to interact with the user through voice.
+ * @hide
*/
public class VoiceInteractor {
static final String TAG = "VoiceInteractor";
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/task/ITaskCallback.aidl
index ffa57d1..d8a32fd 100644
--- a/core/java/android/app/task/ITaskCallback.aidl
+++ b/core/java/android/app/task/ITaskCallback.aidl
@@ -34,14 +34,17 @@
* Immediate callback to the system after sending a start signal, used to quickly detect ANR.
*
* @param taskId Unique integer used to identify this task.
+ * @param ongoing True to indicate that the client is processing the task. False if the task is
+ * complete
*/
- void acknowledgeStartMessage(int taskId);
+ void acknowledgeStartMessage(int taskId, boolean ongoing);
/**
* Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
*
* @param taskId Unique integer used to identify this task.
+ * @param rescheulde Whether or not to reschedule this task.
*/
- void acknowledgeStopMessage(int taskId);
+ void acknowledgeStopMessage(int taskId, boolean reschedule);
/*
* Tell the task manager that the client is done with its execution, so that it can go on to
* the next one and stop attributing wakelock time to us etc.
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
index 81333be..ab1a565 100644
--- a/core/java/android/app/task/TaskService.java
+++ b/core/java/android/app/task/TaskService.java
@@ -18,7 +18,6 @@
import android.app.Service;
import android.content.Intent;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -124,22 +123,20 @@
switch (msg.what) {
case MSG_EXECUTE_TASK:
try {
- TaskService.this.onStartTask(params);
+ boolean workOngoing = TaskService.this.onStartTask(params);
+ ackStartMessage(params, workOngoing);
} catch (Exception e) {
Log.e(TAG, "Error while executing task: " + params.getTaskId());
throw new RuntimeException(e);
- } finally {
- maybeAckMessageReceived(params, MSG_EXECUTE_TASK);
}
break;
case MSG_STOP_TASK:
try {
- TaskService.this.onStopTask(params);
+ boolean ret = TaskService.this.onStopTask(params);
+ ackStopMessage(params, ret);
} catch (Exception e) {
Log.e(TAG, "Application unable to handle onStopTask.", e);
throw new RuntimeException(e);
- } finally {
- maybeAckMessageReceived(params, MSG_STOP_TASK);
}
break;
case MSG_TASK_FINISHED:
@@ -162,30 +159,34 @@
}
}
- /**
- * Messages come in on the application's main thread, so rather than run the risk of
- * waiting for an app that may be doing something foolhardy, we ack to the system after
- * processing a message. This allows us to throw up an ANR dialogue as quickly as possible.
- * @param params id of the task we're acking.
- * @param state Information about what message we're acking.
- */
- private void maybeAckMessageReceived(TaskParams params, int state) {
+ private void ackStartMessage(TaskParams params, boolean workOngoing) {
final ITaskCallback callback = params.getCallback();
final int taskId = params.getTaskId();
if (callback != null) {
try {
- if (state == MSG_EXECUTE_TASK) {
- callback.acknowledgeStartMessage(taskId);
- } else if (state == MSG_STOP_TASK) {
- callback.acknowledgeStopMessage(taskId);
- }
+ callback.acknowledgeStartMessage(taskId, workOngoing);
} catch(RemoteException e) {
Log.e(TAG, "System unreachable for starting task.");
}
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, state + ": Attempting to ack a task that has already been" +
- "processed.");
+ Log.d(TAG, "Attempting to ack a task that has already been processed.");
+ }
+ }
+ }
+
+ private void ackStopMessage(TaskParams params, boolean reschedule) {
+ final ITaskCallback callback = params.getCallback();
+ final int taskId = params.getTaskId();
+ if (callback != null) {
+ try {
+ callback.acknowledgeStopMessage(taskId, reschedule);
+ } catch(RemoteException e) {
+ Log.e(TAG, "System unreachable for stopping task.");
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Attempting to ack a task that has already been processed.");
}
}
}
@@ -203,12 +204,14 @@
*
* @param params Parameters specifying info about this task, including the extras bundle you
* optionally provided at task-creation time.
+ * @return True if your service needs to process the work (on a separate thread). False if
+ * there's no more work to be done for this task.
*/
- public abstract void onStartTask(TaskParams params);
+ public abstract boolean onStartTask(TaskParams params);
/**
- * This method is called if your task should be stopped even before you've called
- * {@link #taskFinished(TaskParams, boolean)}.
+ * This method is called if the system has determined that you must stop execution of your task
+ * even before you've had a chance to call {@link #taskFinished(TaskParams, boolean)}.
*
* <p>This will happen if the requirements specified at schedule time are no longer met. For
* example you may have requested WiFi with
@@ -217,33 +220,27 @@
* {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
* idle maintenance window. You are solely responsible for the behaviour of your application
* upon receipt of this message; your app will likely start to misbehave if you ignore it. One
- * repercussion is that the system will cease to hold a wakelock for you.</p>
- *
- * <p>After you've done your clean-up you are still expected to call
- * {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and
- * allow you to reschedule your task as it is probably uncompleted. Until you call
- * taskFinished() you will not receive any newly scheduled tasks with the given task id as the
- * TaskManager will consider the task to be in an error state.</p>
+ * immediate repercussion is that the system will cease holding a wakelock for you.</p>
*
* @param params Parameters specifying info about this task.
* @return True to indicate to the TaskManager whether you'd like to reschedule this task based
- * on the criteria provided at task creation-time. False to drop the task. Regardless of the
- * value returned, your task must stop executing.
+ * on the retry criteria provided at task creation-time. False to drop the task. Regardless of
+ * the value returned, your task must stop executing.
*/
public abstract boolean onStopTask(TaskParams params);
/**
- * Callback to inform the TaskManager you have completed execution. This can be called from any
+ * Callback to inform the TaskManager you've finished executing. This can be called from any
* thread, as it will ultimately be run on your application's main thread. When the system
* receives this message it will release the wakelock being held.
* <p>
- * You can specify post-execution behaviour to the scheduler here with <code>needsReschedule
- * </code>. This will apply a back-off timer to your task based on the default, or what was
- * set with {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The
- * original requirements are always honoured even for a backed-off task.
- * Note that a task running in idle mode will not be backed-off. Instead what will happen
- * is the task will be re-added to the queue and re-executed within a future idle
- * maintenance window.
+ * You can specify post-execution behaviour to the scheduler here with
+ * <code>needsReschedule </code>. This will apply a back-off timer to your task based on
+ * the default, or what was set with
+ * {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The original
+ * requirements are always honoured even for a backed-off task. Note that a task running in
+ * idle mode will not be backed-off. Instead what will happen is the task will be re-added
+ * to the queue and re-executed within a future idle maintenance window.
* </p>
*
* @param params Parameters specifying system-provided info about this task, this was given to
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 00fd7ce..b98e5ae 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -81,8 +81,8 @@
*/
public final class BluetoothSocket implements Closeable {
private static final String TAG = "BluetoothSocket";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
+ private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
/** @hide */
public static final int MAX_RFCOMM_CHANNEL = 30;
@@ -185,7 +185,7 @@
BluetoothSocket as = new BluetoothSocket(this);
as.mSocketState = SocketState.CONNECTED;
FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
- if (VDBG) Log.d(TAG, "socket fd passed by stack fds: " + fds);
+ if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + fds);
if(fds == null || fds.length != 1) {
Log.e(TAG, "socket fd passed from stack failed, fds: " + fds);
as.close();
@@ -352,24 +352,24 @@
// read out port number
try {
synchronized(this) {
- if (VDBG) Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " +
+ if (DBG) Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " +
mPfd);
if(mSocketState != SocketState.INIT) return EBADFD;
if(mPfd == null) return -1;
FileDescriptor fd = mPfd.getFileDescriptor();
- if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket ");
+ if (DBG) Log.d(TAG, "bindListen(), new LocalSocket ");
mSocket = new LocalSocket(fd);
- if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
+ if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
mSocketIS = mSocket.getInputStream();
mSocketOS = mSocket.getOutputStream();
}
- if (VDBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
+ if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
int channel = readInt(mSocketIS);
synchronized(this) {
if(mSocketState == SocketState.INIT)
mSocketState = SocketState.LISTENING;
}
- if (VDBG) Log.d(TAG, "channel: " + channel);
+ if (DBG) Log.d(TAG, "channel: " + channel);
if (mPort == -1) {
mPort = channel;
} // else ASSERT(mPort == channel)
@@ -439,7 +439,7 @@
@Override
public void close() throws IOException {
- if (VDBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
+ if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
if(mSocketState == SocketState.CLOSED)
return;
else
@@ -449,10 +449,10 @@
if(mSocketState == SocketState.CLOSED)
return;
mSocketState = SocketState.CLOSED;
- if (VDBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
+ if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
", mSocketOS: " + mSocketOS + "mSocket: " + mSocket);
if(mSocket != null) {
- if (VDBG) Log.d(TAG, "Closing mSocket: " + mSocket);
+ if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
mSocket.shutdownInput();
mSocket.shutdownOutput();
mSocket.close();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a059e48..c11b04c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1499,6 +1499,17 @@
@Nullable Bundle initialExtras);
/**
+ * Similar to above but takes an appOp as well, to enforce restrictions.
+ * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String,
+ * BroadcastReceiver, Handler, int, String, Bundle)
+ * @hide
+ */
+ public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ @Nullable String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras);
+
+ /**
* Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
* Intent you are sending stays around after the broadcast is complete,
* so that others can quickly retrieve that data through the return
@@ -1980,7 +1991,7 @@
//@hide: NETWORK_STATS_SERVICE,
//@hide: NETWORK_POLICY_SERVICE,
WIFI_SERVICE,
- WIFI_HOTSPOT_SERVICE,
+ WIFI_PASSPOINT_SERVICE,
WIFI_P2P_SERVICE,
WIFI_SCANNING_SERVICE,
NSD_SERVICE,
@@ -2341,13 +2352,13 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.net.wifi.hotspot.WifiHotspotManager} for handling management of
- * Wi-Fi hotspot access.
+ * android.net.wifi.passpoint.PasspointManager} for handling management of
+ * Wi-Fi passpoint access.
*
* @see #getSystemService
- * @see android.net.wifi.hotspot.WifiHotspotManager
+ * @see android.net.wifi.passpoint.PasspointManager
*/
- public static final String WIFI_HOTSPOT_SERVICE = "wifihotspot";
+ public static final String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
/**
* Use with {@link #getSystemService} to retrieve a {@link
@@ -2411,10 +2422,10 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.media.session.SessionManager} for managing media Sessions.
+ * {@link android.media.session.MediaSessionManager} for managing media Sessions.
*
* @see #getSystemService
- * @see android.media.session.SessionManager
+ * @see android.media.session.MediaSessionManager
*/
public static final String MEDIA_SESSION_SERVICE = "media_session";
@@ -2572,13 +2583,24 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.hardware.hdmi.HdmiCecManager for controlling and managing
+ * {@link android.hardware.hdmi.HdmiCecManager} for controlling and managing
* HDMI-CEC protocol.
*
* @see #getSystemService
* @see android.hardware.hdmi.HdmiCecManager
*/
- public static final String HDMI_CEC_SERVICE = "hdmi_cec";
+ // TODO: Remove this once HdmiControlService is ready.
+ public static final String HDMI_CEC_SERVICE = "hdmi_cec";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.hardware.hdmi.HdmiControlManager} for controlling and managing
+ * HDMI-CEC protocol.
+ *
+ * @see #getSystemService
+ * @see android.hardware.hdmi.HdmiControlManager
+ */
+ public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
/**
* Use with {@link #getSystemService} to retrieve a
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 93f6cdf..c66355b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -418,6 +418,16 @@
scheduler, initialCode, initialData, initialExtras);
}
+ /** @hide */
+ @Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ Handler scheduler,
+ int initialCode, String initialData, Bundle initialExtras) {
+ mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver,
+ scheduler, initialCode, initialData, initialExtras);
+ }
+
@Override
public void sendStickyBroadcast(Intent intent) {
mBase.sendStickyBroadcast(intent);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 076f657..fed63d2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2809,6 +2809,7 @@
* An activity that supports this category must be prepared to run with
* no UI shown at all (though in some case it may have a UI shown), and
* rely on {@link android.app.VoiceInteractor} to interact with the user.
+ * @hide
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 197e3ff..a75372f 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -42,12 +42,8 @@
public class CursorWindow extends SQLiteClosable implements Parcelable {
private static final String STATS_TAG = "CursorWindowStats";
- /** The cursor window size. resource xml file specifies the value in kB.
- * convert it to bytes here by multiplying with 1024.
- */
- private static final int sCursorWindowSize =
- Resources.getSystem().getInteger(
- com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+ // This static member will be evaluated when first used.
+ private static int sCursorWindowSize = -1;
/**
* The native CursorWindow object pointer. (FOR INTERNAL USE ONLY)
@@ -100,6 +96,13 @@
public CursorWindow(String name) {
mStartPos = 0;
mName = name != null && name.length() != 0 ? name : "<unnamed>";
+ if (sCursorWindowSize < 0) {
+ /** The cursor window size. resource xml file specifies the value in kB.
+ * convert it to bytes here by multiplying with 1024.
+ */
+ sCursorWindowSize = Resources.getSystem().getInteger(
+ com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+ }
mWindowPtr = nativeCreate(mName, sCursorWindowSize);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index b1c1005..7cc6d1d 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -17,6 +17,7 @@
package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
import java.util.Collections;
import java.util.List;
@@ -29,6 +30,8 @@
* through the {@link CameraManager CameraManager}
* interface in addition to through the CameraDevice interface.</p>
*
+ * <p>{@link CameraCharacteristics} objects are immutable.</p>
+ *
* @see CameraDevice
* @see CameraManager
*/
@@ -46,6 +49,14 @@
mProperties = properties;
}
+ /**
+ * Returns a copy of the underlying {@link CameraMetadataNative}.
+ * @hide
+ */
+ public CameraMetadataNative getNativeCopy() {
+ return new CameraMetadataNative(mProperties);
+ }
+
@Override
public <T> T get(Key<T> key) {
return mProperties.get(key);
@@ -316,8 +327,8 @@
* <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
* </ul>
*/
- public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
- new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
+ public static final Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
+ new Key<android.util.Size[]>("android.jpeg.availableThumbnailSizes", android.util.Size[].class);
/**
* <p>List of supported aperture
@@ -393,8 +404,8 @@
* <p>The map should be on the order of 30-40 rows and columns, and
* must be smaller than 64x64.</p>
*/
- public static final Key<android.hardware.camera2.Size> LENS_INFO_SHADING_MAP_SIZE =
- new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
+ public static final Key<android.util.Size> LENS_INFO_SHADING_MAP_SIZE =
+ new Key<android.util.Size>("android.lens.info.shadingMapSize", android.util.Size.class);
/**
* <p>The lens focus distance calibration quality.</p>
@@ -658,8 +669,8 @@
* @hide
*/
@Deprecated
- public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
- new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
+ public static final Key<android.util.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
+ new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
/**
* <p>The maximum ratio between active area width
@@ -704,8 +715,8 @@
* @hide
*/
@Deprecated
- public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
- new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
+ public static final Key<android.util.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
+ new Key<android.util.Size[]>("android.scaler.availableProcessedSizes", android.util.Size[].class);
/**
* <p>The mapping of image formats that are supported by this
@@ -961,9 +972,6 @@
* can provide.</p>
* <p>Please reference the documentation for the image data destination to
* check if it limits the maximum size for image data.</p>
- * <p>Not all output formats may be supported in a configuration with
- * an input stream of a particular format. For more details, see
- * android.scaler.availableInputOutputFormatsMap.</p>
* <p>The following table describes the minimum required output stream
* configurations based on the hardware level
* ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
@@ -1106,8 +1114,8 @@
* match this in
* android.scaler.availableStreamConfigurations.</p>
*/
- public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
- new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
+ public static final Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
+ new Key<android.util.Size>("android.sensor.info.pixelArraySize", android.util.Size.class);
/**
* <p>Maximum raw value output by sensor.</p>
@@ -1515,13 +1523,4 @@
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 8ae21f3..a70aa3b 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -19,6 +19,7 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Rational;
import android.view.Surface;
import java.util.HashSet;
@@ -169,7 +170,7 @@
* @param in The parcel from which the object should be read
* @hide
*/
- public void readFromParcel(Parcel in) {
+ private void readFromParcel(Parcel in) {
mSettings.readFromParcel(in);
mSurfaceSet.clear();
@@ -965,8 +966,8 @@
* <p>When a jpeg image capture is issued, the thumbnail size selected should have
* the same aspect ratio as the jpeg image.</p>
*/
- public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
- new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+ public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+ new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
/**
* <p>The ratio of lens focal length to the effective
@@ -1518,12 +1519,4 @@
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
}
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0160622..f91fcb9 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -17,6 +17,8 @@
package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.Face;
+import android.util.Rational;
/**
* <p>The results of a single image capture from the image sensor.</p>
@@ -31,6 +33,8 @@
* capture. The result also includes additional metadata about the state of the
* camera device during the capture.</p>
*
+ * <p>{@link CameraCharacteristics} objects are immutable.</p>
+ *
*/
public final class CaptureResult extends CameraMetadata {
@@ -56,6 +60,14 @@
mSequenceId = sequenceId;
}
+ /**
+ * Returns a copy of the underlying {@link CameraMetadataNative}.
+ * @hide
+ */
+ public CameraMetadataNative getNativeCopy() {
+ return new CameraMetadataNative(mResults);
+ }
+
@Override
public <T> T get(Key<T> key) {
return mResults.get(key);
@@ -1512,8 +1524,8 @@
* <p>When a jpeg image capture is issued, the thumbnail size selected should have
* the same aspect ratio as the jpeg image.</p>
*/
- public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
- new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+ public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+ new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
/**
* <p>The ratio of lens focal length to the effective
@@ -2060,6 +2072,16 @@
new Key<byte[]>("android.statistics.faceScores", byte[].class);
/**
+ * <p>List of the faces detected through camera face detection
+ * in this result.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} <code>!=</code> OFF.</p>
+ *
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+ */
+ public static final Key<android.hardware.camera2.params.Face[]> STATISTICS_FACES =
+ new Key<android.hardware.camera2.params.Face[]>("android.statistics.faces", android.hardware.camera2.params.Face[].class);
+
+ /**
* <p>The shading map is a low-resolution floating-point map
* that lists the coefficients used to correct for vignetting, for each
* Bayer color channel.</p>
@@ -2425,27 +2447,4 @@
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
- /**
- * <p>
- * List of the {@link Face Faces} detected through camera face detection
- * in this result.
- * </p>
- * <p>
- * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
- * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
- * </p>
- *
- * @see Face
- */
- public static final Key<Face[]> STATISTICS_FACES =
- new Key<Face[]>("android.statistics.faces", Face[].class);
}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index a14d38b..caabed3 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -17,7 +17,7 @@
package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.CaptureResultExtras;
+import android.hardware.camera2.impl.CaptureResultExtras;
/** @hide */
interface ICameraDeviceCallbacks
diff --git a/core/java/android/hardware/camera2/Size.java b/core/java/android/hardware/camera2/Size.java
deleted file mode 100644
index 9328a003..0000000
--- a/core/java/android/hardware/camera2/Size.java
+++ /dev/null
@@ -1,102 +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.hardware.camera2;
-
-// TODO: Delete this class, since it was moved to android.util as public API
-
-/**
- * Immutable class for describing width and height dimensions in pixels.
- *
- * @hide
- */
-public final class Size {
- /**
- * Create a new immutable Size instance.
- *
- * @param width The width of the size, in pixels
- * @param height The height of the size, in pixels
- */
- public Size(final int width, final int height) {
- mWidth = width;
- mHeight = height;
- }
-
- /**
- * Get the width of the size (in pixels).
- * @return width
- */
- public final int getWidth() {
- return mWidth;
- }
-
- /**
- * Get the height of the size (in pixels).
- * @return height
- */
- public final int getHeight() {
- return mHeight;
- }
-
- /**
- * Check if this size is equal to another size.
- * <p>
- * Two sizes are equal if and only if both their widths and heights are
- * equal.
- * </p>
- * <p>
- * A size object is never equal to any other type of object.
- * </p>
- *
- * @return {@code true} if the objects were equal, {@code false} otherwise
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof Size) {
- final Size other = (Size) obj;
- return mWidth == other.mWidth && mHeight == other.mHeight;
- }
- return false;
- }
-
- /**
- * Return the size represented as a string with the format {@code "WxH"}
- *
- * @return string representation of the size
- */
- @Override
- public String toString() {
- return mWidth + "x" + mHeight;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
- return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
- }
-
- private final int mWidth;
- private final int mHeight;
-};
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 628d1c3..dba24a1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -21,7 +21,6 @@
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.utils.CameraBinderDecorator;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index d28f7bd..db7486d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -22,7 +22,6 @@
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Face;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
import android.hardware.camera2.marshal.MarshalRegistry;
@@ -43,6 +42,7 @@
import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
import android.hardware.camera2.marshal.impl.MarshalQueryableString;
+import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.params.StreamConfigurationDuration;
import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
similarity index 94%
rename from core/java/android/hardware/camera2/CaptureResultExtras.aidl
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
index 6587f02..ebc812a 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.aidl
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
/** @hide */
parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
similarity index 98%
rename from core/java/android/hardware/camera2/CaptureResultExtras.java
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.java
index e5c2c1c..b3a9559 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.java
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
index fd72ee2..35ecc2a 100644
--- a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
+++ b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
@@ -18,8 +18,8 @@
import static android.hardware.camera2.impl.CameraMetadataNative.*;
import static com.android.internal.util.Preconditions.*;
-import android.hardware.camera2.Rational;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
/**
* Static functions in order to help implementing various marshaler functionality.
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
index d3796db..47f79bf 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
@@ -15,9 +15,9 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.ColorSpaceTransform;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.ColorSpaceTransform;
import android.hardware.camera2.utils.TypeReference;
import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
index c8b9bd8..01780db 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
@@ -15,9 +15,9 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.MeteringRectangle;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.utils.TypeReference;
import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
index 708da70..189b597 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
@@ -15,11 +15,11 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.Rational;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
import android.hardware.camera2.utils.TypeReference;
+import android.util.Rational;
import static android.hardware.camera2.impl.CameraMetadataNative.*;
import static android.hardware.camera2.marshal.MarshalHelpers.*;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
index 93c0e92..4253a0a 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
@@ -15,9 +15,9 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.RggbChannelVector;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.RggbChannelVector;
import android.hardware.camera2.utils.TypeReference;
import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
index 6a73bee..721644e 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
@@ -15,7 +15,7 @@
*/
package android.hardware.camera2.marshal.impl;
-import android.hardware.camera2.Size;
+import android.util.Size;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
import android.hardware.camera2.utils.TypeReference;
diff --git a/core/java/android/hardware/camera2/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
similarity index 98%
rename from core/java/android/hardware/camera2/ColorSpaceTransform.java
rename to core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index 5e4c0a2..fa8c8ea 100644
--- a/core/java/android/hardware/camera2/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import static com.android.internal.util.Preconditions.*;
+import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Rational;
import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/params/Face.java
similarity index 97%
rename from core/java/android/hardware/camera2/Face.java
rename to core/java/android/hardware/camera2/params/Face.java
index ded8839d..2cd83a3 100644
--- a/core/java/android/hardware/camera2/Face.java
+++ b/core/java/android/hardware/camera2/params/Face.java
@@ -15,10 +15,13 @@
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureResult;
/**
* Describes a face detected in an image.
diff --git a/core/java/android/hardware/camera2/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
similarity index 97%
rename from core/java/android/hardware/camera2/LensShadingMap.java
rename to core/java/android/hardware/camera2/params/LensShadingMap.java
index 2b0108c..b328f578 100644
--- a/core/java/android/hardware/camera2/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.RggbChannelVector.*;
+import static android.hardware.camera2.params.RggbChannelVector.*;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.utils.HashCodeHelpers;
import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/MeteringRectangle.java b/core/java/android/hardware/camera2/params/MeteringRectangle.java
similarity index 97%
rename from core/java/android/hardware/camera2/MeteringRectangle.java
rename to core/java/android/hardware/camera2/params/MeteringRectangle.java
index bb8e5b1..a26c57d 100644
--- a/core/java/android/hardware/camera2/MeteringRectangle.java
+++ b/core/java/android/hardware/camera2/params/MeteringRectangle.java
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import android.util.Size;
import static com.android.internal.util.Preconditions.*;
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.HashCodeHelpers;
/**
diff --git a/core/java/android/hardware/camera2/RggbChannelVector.java b/core/java/android/hardware/camera2/params/RggbChannelVector.java
similarity index 99%
rename from core/java/android/hardware/camera2/RggbChannelVector.java
rename to core/java/android/hardware/camera2/params/RggbChannelVector.java
index 80167c6..30591f6 100644
--- a/core/java/android/hardware/camera2/RggbChannelVector.java
+++ b/core/java/android/hardware/camera2/params/RggbChannelVector.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import static com.android.internal.util.Preconditions.*;
diff --git a/core/java/android/hardware/camera2/TonemapCurve.java b/core/java/android/hardware/camera2/params/TonemapCurve.java
similarity index 97%
rename from core/java/android/hardware/camera2/TonemapCurve.java
rename to core/java/android/hardware/camera2/params/TonemapCurve.java
index 2958ebf..0fcffac 100644
--- a/core/java/android/hardware/camera2/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/params/TonemapCurve.java
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.hardware.camera2.params;
import static com.android.internal.util.Preconditions.*;
import android.graphics.PointF;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.HashCodeHelpers;
import java.util.Arrays;
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 9193f89..a71a74d 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -171,8 +171,15 @@
public static final int POWER_STATUS_UNKNOWN = -1;
public static final int POWER_STATUS_ON = 0;
public static final int POWER_STATUS_STANDBY = 1;
- public static final int POWER_TRANSIENT_TO_ON = 2;
- public static final int POWER_TRANSIENT_TO_STANDBY = 3;
+ public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
+ public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
+
+ public static final int RESULT_SUCCESS = 0;
+ public static final int RESULT_TIMEOUT = 1;
+ public static final int RESULT_SOURCE_NOT_AVAILABLE = 2;
+ public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
+ public static final int RESULT_ALREADY_IN_PROGRESS = 4;
+ public static final int RESULT_EXCEPTION = 5;
private static final int[] ADDRESS_TO_TYPE = {
DEVICE_TV, // ADDR_TV
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
new file mode 100644
index 0000000..a3f27b9
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -0,0 +1,76 @@
+/*
+ * 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.hdmi;
+
+import android.annotation.Nullable;
+/**
+ * The {@link HdmiControlManager} class is used to send HDMI control messages
+ * to attached CEC devices.
+ *
+ * <p>Provides various HDMI client instances that represent HDMI-CEC logical devices
+ * hosted in the system. {@link #getTvClient()}, for instance will return an
+ * {@link HdmiTvClient} object if the system is configured to host one. Android system
+ * can host more than one logical CEC devices. If multiple types are configured they
+ * all work as if they were independent logical devices running in the system.
+ */
+public final class HdmiControlManager {
+ @Nullable private final IHdmiControlService mService;
+
+ /**
+ * @hide - hide this constructor because it has a parameter of type
+ * IHdmiControlService, which is a system private class. The right way
+ * to create an instance of this class is using the factory
+ * Context.getSystemService.
+ */
+ public HdmiControlManager(IHdmiControlService service) {
+ mService = service;
+ }
+
+ /**
+ * Gets an object that represents a HDMI-CEC logical device of type playback on the system.
+ *
+ * <p>Used to send HDMI control messages to other devices like TV or audio amplifier through
+ * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
+ * system if the system is configured to host more than one type of HDMI-CEC logical devices.
+ *
+ * @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
+ */
+ @Nullable
+ public HdmiPlaybackClient getPlaybackClient() {
+ if (mService == null) {
+ return null;
+ }
+ return new HdmiPlaybackClient(mService);
+ }
+
+ /**
+ * Gets an object that represents a HDMI-CEC logical device of type TV on the system.
+ *
+ * <p>Used to send HDMI control messages to other devices and manage them through
+ * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
+ * system if the system is configured to host more than one type of HDMI-CEC logical devices.
+ *
+ * @return {@link HdmiTvClient} instance. {@code null} on failure.
+ */
+ @Nullable
+ public HdmiTvClient getTvClient() {
+ if (mService == null) {
+ return null;
+ }
+ return new HdmiTvClient(mService);
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
new file mode 100644
index 0000000..83da29a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -0,0 +1,116 @@
+/*
+ * 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.hdmi;
+
+import android.os.RemoteException;
+
+import android.util.Log;
+
+/**
+ * HdmiPlaybackClient represents HDMI-CEC logical device of type Playback
+ * in the Android system which acts as a playback device such as set-top box.
+ * It provides with methods that control, get information from TV/Display device
+ * connected through HDMI bus.
+ */
+public final class HdmiPlaybackClient {
+ private static final String TAG = "HdmiPlaybackClient";
+
+ private final IHdmiControlService mService;
+
+ /**
+ * Listener used by the client to get the result of one touch play operation.
+ */
+ public interface OneTouchPlayCallback {
+ /**
+ * Called when the result of the feature one touch play is returned.
+ *
+ * @param result the result of the operation. {@link HdmiCec#RESULT_SUCCESS}
+ * if successful.
+ */
+ public void onComplete(int result);
+ }
+
+ /**
+ * Listener used by the client to get display device status.
+ */
+ public interface DisplayStatusCallback {
+ /**
+ * Called when display device status is reported.
+ *
+ * @param status display device status
+ * @see {@link HdmiCec#POWER_STATUS_ON}
+ * @see {@link HdmiCec#POWER_STATUS_STANDBY}
+ * @see {@link HdmiCec#POWER_STATUS_TRANSIENT_TO_ON}
+ * @see {@link HdmiCec#POWER_STATUS_TRANSIENT_TO_STANDBY}
+ * @see {@link HdmiCec#POWER_STATUS_UNKNOWN}
+ */
+ public void onComplete(int status);
+ }
+
+ HdmiPlaybackClient(IHdmiControlService service) {
+ mService = service;
+ }
+
+ /**
+ * Perform the feature 'one touch play' from playback device to turn on display
+ * and switch the input.
+ *
+ * @param callback {@link OneTouchPlayCallback} object to get informed
+ * of the result
+ */
+ public void oneTouchPlay(OneTouchPlayCallback callback) {
+ // TODO: Use PendingResult.
+ try {
+ mService.oneTouchPlay(getCallbackWrapper(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "oneTouchPlay threw exception ", e);
+ }
+ }
+
+ /**
+ * Get the status of display device connected through HDMI bus.
+ *
+ * @param callback {@link DisplayStatusCallback} object to get informed
+ * of the result
+ */
+ public void queryDisplayStatus(DisplayStatusCallback callback) {
+ // TODO: PendingResult.
+ try {
+ mService.oneTouchPlay(getCallbackWrapper(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "queryDisplayStatus threw exception ", e);
+ }
+ }
+
+ private IHdmiControlCallback getCallbackWrapper(final OneTouchPlayCallback callback) {
+ return new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ callback.onComplete(result);
+ }
+ };
+ }
+
+ private IHdmiControlCallback getCallbackWrapper(final DisplayStatusCallback callback) {
+ return new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int status) {
+ callback.onComplete(status);
+ }
+ };
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
new file mode 100644
index 0000000..73c72472
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -0,0 +1,31 @@
+/*
+ * 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.hdmi;
+
+/**
+ * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
+ * which acts as TV/Display. It provides with methods that manage, interact with other
+ * devices on the CEC bus.
+ */
+public final class HdmiTvClient {
+ private static final String TAG = "HdmiTvClient";
+
+ private final IHdmiControlService mService;
+
+ HdmiTvClient(IHdmiControlService service) {
+ mService = service;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/core/java/android/hardware/hdmi/IHdmiControlCallback.aidl
similarity index 72%
copy from packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
copy to core/java/android/hardware/hdmi/IHdmiControlCallback.aidl
index 158e9c1..ef3dd47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
+++ b/core/java/android/hardware/hdmi/IHdmiControlCallback.aidl
@@ -14,9 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.policy;
+package android.hardware.hdmi;
-/** Common interface for items requiring manual cleanup. **/
-public interface Disposable {
- void dispose();
+/**
+ * Callback interface definition for HDMI client to get informed of
+ * the result of various API invocation.
+ *
+ * @hide
+ */
+oneway interface IHdmiControlCallback {
+ void onComplete(int result);
}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
new file mode 100644
index 0000000..f790ed9
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+
+/**
+ * Binder interface that clients running in the application process
+ * will use to perform HDMI-CEC features by communicating with other devices
+ * on the bus.
+ *
+ * @hide
+ */
+interface IHdmiControlService {
+ int oneTouchPlay(IHdmiControlCallback callback);
+ int queryDisplayStatus(IHdmiControlCallback callback);
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a414421..1837335 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -21,6 +21,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
@@ -57,13 +58,15 @@
* is lost</li>
* <li>Provide an API that allows applications to query the coarse-grained or fine-grained
* state of the available networks</li>
+ * <li>Provide an API that allows applications to request and select networks for their data
+ * traffic</li>
* </ol>
*/
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
/**
- * A change in network connectivity has occurred. A connection has either
+ * A change in network connectivity has occurred. A default connection has either
* been established or lost. The NetworkInfo for the affected network is
* sent as an extra; it should be consulted to see what kind of
* connectivity event occurred.
@@ -547,13 +550,12 @@
* @param preference the network type to prefer over all others. It is
* unspecified what happens to the old preferred network in the
* overall ordering.
+ * @deprecated Functionality has been removed as it no longer makes sense,
+ * with many more than two networks - we'd need an array to express
+ * preference. Instead we use dynamic network properties of
+ * the networks to describe their precedence.
*/
public void setNetworkPreference(int preference) {
- // TODO - deprecate with:
- // @deprecated Functionality has been removed as it no longer makes sense,
- // with many more than two networks - we'd need an array to express
- // preference. Instead we use dynamic network properties of
- // the networks to describe their precedence.
}
/**
@@ -563,14 +565,13 @@
*
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ * @deprecated Functionality has been removed as it no longer makes sense,
+ * with many more than two networks - we'd need an array to express
+ * preference. Instead we use dynamic network properties of
+ * the networks to describe their precedence.
*/
public int getNetworkPreference() {
- // TODO - deprecate with:
- // @deprecated Functionality has been removed as it no longer makes sense,
- // with many more than two networks - we'd need an array to express
- // preference. Instead we use dynamic network properties of
- // the networks to describe their precedence.
- return -1;
+ return TYPE_NONE;
}
/**
@@ -716,7 +717,13 @@
}
}
- /** {@hide} */
+ /**
+ * Get the {@link LinkProperties} for the given {@link Network}. This
+ * will return {@code null} if the network is unknown.
+ *
+ * @param network The {@link Network} object identifying the network in question.
+ * @return The {@link LinkProperties} for the network, or {@code null}.
+ **/
public LinkProperties getLinkProperties(Network network) {
try {
return mService.getLinkProperties(network);
@@ -725,7 +732,13 @@
}
}
- /** {@hide} */
+ /**
+ * Get the {@link NetworkCapabilities} for the given {@link Network}. This
+ * will return {@code null} if the network is unknown.
+ *
+ * @param network The {@link Network} object identifying the network in question.
+ * @return The {@link NetworkCapabilities} for the network, or {@code null}.
+ */
public NetworkCapabilities getNetworkCapabilities(Network network) {
try {
return mService.getNetworkCapabilities(network);
@@ -788,6 +801,8 @@
* The interpretation of this value is specific to each networking
* implementation+feature combination, except that the value {@code -1}
* always indicates failure.
+ *
+ * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
*/
public int startUsingNetworkFeature(int networkType, String feature) {
try {
@@ -810,6 +825,8 @@
* The interpretation of this value is specific to each networking
* implementation+feature combination, except that the value {@code -1}
* always indicates failure.
+ *
+ * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
*/
public int stopUsingNetworkFeature(int networkType, String feature) {
try {
@@ -829,6 +846,9 @@
* host is to be routed
* @param hostAddress the IP address of the host to which the route is desired
* @return {@code true} on success, {@code false} on failure
+ *
+ * @deprecated Deprecated in favor of the {@link #requestNetwork},
+ * {@link Network#bindProcess} and {@link Network#socketFactory} api.
*/
public boolean requestRouteToHost(int networkType, int hostAddress) {
InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
@@ -851,6 +871,8 @@
* @param hostAddress the IP address of the host to which the route is desired
* @return {@code true} on success, {@code false} on failure
* @hide
+ * @deprecated Deprecated in favor of the {@link #requestNetwork} and
+ * {@link Network#bindProcess} api.
*/
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
byte[] address = hostAddress.getAddress();
@@ -1332,13 +1354,13 @@
}
/**
- * Report a problem network to the framework. This will cause the framework
- * to evaluate the situation and try to fix any problems. Note that false
- * may be subsequently ignored.
+ * Report a problem network to the framework. This provides a hint to the system
+ * that there might be connectivity problems on this network and may cause
+ * the framework to re-evaluate network connectivity and/or switch to another
+ * network.
*
- * @param network The Network the application was attempting to use or null
- * to indicate the current default network.
- * {@hide}
+ * @param network The {@link Network} the application was attempting to use
+ * or {@code null} to indicate the current default network.
*/
public void reportBadNetwork(Network network) {
try {
@@ -1358,6 +1380,7 @@
*
* <p>This method requires the call to hold the permission
* android.Manifest.permission#CONNECTIVITY_INTERNAL.
+ * @hide
*/
public void setGlobalProxy(ProxyInfo p) {
try {
@@ -1374,6 +1397,7 @@
*
* <p>This method requires the call to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ * @hide
*/
public ProxyInfo getGlobalProxy() {
try {
@@ -1393,6 +1417,7 @@
* <p>This method requires the call to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
* {@hide}
+ * @deprecated Deprecated in favor of {@link #getLinkProperties}
*/
public ProxyInfo getProxy() {
try {
@@ -1645,11 +1670,10 @@
}
/**
- * Interface for NetworkRequest callbacks. Used for notifications about network
- * changes.
- * @hide
+ * Base class for NetworkRequest callbacks. Used for notifications about network
+ * changes. Should be extended by applications wanting notifications.
*/
- public static class NetworkCallbacks {
+ public static class NetworkCallbackListener {
/** @hide */
public static final int PRECHECK = 1;
/** @hide */
@@ -1675,51 +1699,73 @@
public void onPreCheck(NetworkRequest networkRequest, Network network) {}
/**
- * Called when the framework connects and has validated the new network.
+ * Called when the framework connects and has declared new network ready for use.
+ *
+ * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+ * @param network The {@link Network} of the satisfying network.
*/
public void onAvailable(NetworkRequest networkRequest, Network network) {}
/**
- * Called when the framework is losing the network. Often paired with an
- * onAvailable call with the new replacement network for graceful handover.
- * This may not be called if we have a hard loss (loss without warning).
- * This may be followed by either an onLost call or an onAvailable call for this
- * network depending on if we lose or regain it.
+ * Called when the network is about to be disconnected. Often paired with an
+ * {@link NetworkCallbackListener#onAvailable} call with the new replacement network
+ * for graceful handover. This may not be called if we have a hard loss
+ * (loss without warning). This may be followed by either a
+ * {@link NetworkCallbackListener#onLost} call or a
+ * {@link NetworkCallbackListener#onAvailable} call for this network depending
+ * on whether we lose or regain it.
+ *
+ * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+ * @param network The {@link Network} of the failing network.
+ * @param maxSecToLive The time in seconds the framework will attempt to keep the
+ * network connected. Note that the network may suffers a
+ * hard loss at any time.
*/
public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {}
/**
* Called when the framework has a hard loss of the network or when the
- * graceful failure ends. Note applications should only request this callback
- * if the application is willing to track the Available and Lost callbacks
- * together, else the application may think it has no network when it
- * really does (A Avail, B Avail, A Lost.. still have B).
+ * graceful failure ends.
+ *
+ * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+ * @param network The {@link Network} lost.
*/
public void onLost(NetworkRequest networkRequest, Network network) {}
/**
* Called if no network is found in the given timeout time. If no timeout is given,
* this will not be called.
+ * @hide
*/
public void onUnavailable(NetworkRequest networkRequest) {}
/**
* Called when the network the framework connected to for this request
* changes capabilities but still satisfies the stated need.
+ *
+ * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+ * @param network The {@link Network} whose capabilities have changed.
+ * @param networkCapabilities The new {@link NetworkCapabilities} for this network.
*/
public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network,
NetworkCapabilities networkCapabilities) {}
/**
* Called when the network the framework connected to for this request
- * changes LinkProperties.
+ * changes {@link LinkProperties}.
+ *
+ * @param networkRequest The {@link NetworkRequest} used to initiate the request.
+ * @param network The {@link Network} whose link properties have changed.
+ * @param linkProperties The new {@link LinkProperties} for this network.
*/
public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network,
LinkProperties linkProperties) {}
/**
- * Called when a releaseNetworkRequest call concludes and the registered callbacks will
- * no longer be used.
+ * Called when a {@link #releaseNetworkRequest} call concludes and the registered
+ * callbacks will no longer be used.
+ *
+ * @param networkRequest The {@link NetworkRequest} used to initiate the request.
*/
public void onReleased(NetworkRequest networkRequest) {}
}
@@ -1745,12 +1791,12 @@
public static final int CALLBACK_EXIT = BASE + 9;
private static class CallbackHandler extends Handler {
- private final HashMap<NetworkRequest, NetworkCallbacks>mCallbackMap;
+ private final HashMap<NetworkRequest, NetworkCallbackListener>mCallbackMap;
private final AtomicInteger mRefCount;
private static final String TAG = "ConnectivityManager.CallbackHandler";
private final ConnectivityManager mCm;
- CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbacks>callbackMap,
+ CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbackListener>callbackMap,
AtomicInteger refCount, ConnectivityManager cm) {
super(looper);
mCallbackMap = callbackMap;
@@ -1764,7 +1810,7 @@
switch (message.what) {
case CALLBACK_PRECHECK: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbacks callbacks = getCallbacks(request);
+ NetworkCallbackListener callbacks = getCallbacks(request);
if (callbacks != null) {
callbacks.onPreCheck(request, getNetwork(message));
} else {
@@ -1774,7 +1820,7 @@
}
case CALLBACK_AVAILABLE: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbacks callbacks = getCallbacks(request);
+ NetworkCallbackListener callbacks = getCallbacks(request);
if (callbacks != null) {
callbacks.onAvailable(request, getNetwork(message));
} else {
@@ -1784,7 +1830,7 @@
}
case CALLBACK_LOSING: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbacks callbacks = getCallbacks(request);
+ NetworkCallbackListener callbacks = getCallbacks(request);
if (callbacks != null) {
callbacks.onLosing(request, getNetwork(message), message.arg1);
} else {
@@ -1794,7 +1840,7 @@
}
case CALLBACK_LOST: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbacks callbacks = getCallbacks(request);
+ NetworkCallbackListener callbacks = getCallbacks(request);
if (callbacks != null) {
callbacks.onLost(request, getNetwork(message));
} else {
@@ -1804,7 +1850,7 @@
}
case CALLBACK_UNAVAIL: {
NetworkRequest req = (NetworkRequest)message.obj;
- NetworkCallbacks callbacks = null;
+ NetworkCallbackListener callbacks = null;
synchronized(mCallbackMap) {
callbacks = mCallbackMap.get(req);
}
@@ -1817,7 +1863,7 @@
}
case CALLBACK_CAP_CHANGED: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbacks callbacks = getCallbacks(request);
+ NetworkCallbackListener callbacks = getCallbacks(request);
if (callbacks != null) {
Network network = getNetwork(message);
NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
@@ -1830,7 +1876,7 @@
}
case CALLBACK_IP_CHANGED: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbacks callbacks = getCallbacks(request);
+ NetworkCallbackListener callbacks = getCallbacks(request);
if (callbacks != null) {
Network network = getNetwork(message);
LinkProperties lp = mCm.getLinkProperties(network);
@@ -1843,7 +1889,7 @@
}
case CALLBACK_RELEASED: {
NetworkRequest req = (NetworkRequest)message.obj;
- NetworkCallbacks callbacks = null;
+ NetworkCallbackListener callbacks = null;
synchronized(mCallbackMap) {
callbacks = mCallbackMap.remove(req);
}
@@ -1870,7 +1916,7 @@
private NetworkRequest getNetworkRequest(Message msg) {
return (NetworkRequest)(msg.obj);
}
- private NetworkCallbacks getCallbacks(NetworkRequest req) {
+ private NetworkCallbackListener getCallbacks(NetworkRequest req) {
synchronized(mCallbackMap) {
return mCallbackMap.get(req);
}
@@ -1878,7 +1924,7 @@
private Network getNetwork(Message msg) {
return new Network(msg.arg2);
}
- private NetworkCallbacks removeCallbacks(Message msg) {
+ private NetworkCallbackListener removeCallbacks(Message msg) {
NetworkRequest req = (NetworkRequest)msg.obj;
synchronized(mCallbackMap) {
return mCallbackMap.remove(req);
@@ -1893,7 +1939,7 @@
HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
callbackThread.start();
sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
- sNetworkCallbacks, sCallbackRefCount, this);
+ sNetworkCallbackListener, sCallbackRefCount, this);
}
}
}
@@ -1907,8 +1953,8 @@
}
}
- static final HashMap<NetworkRequest, NetworkCallbacks> sNetworkCallbacks =
- new HashMap<NetworkRequest, NetworkCallbacks>();
+ static final HashMap<NetworkRequest, NetworkCallbackListener> sNetworkCallbackListener =
+ new HashMap<NetworkRequest, NetworkCallbackListener>();
static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
static CallbackHandler sCallbackHandler = null;
@@ -1916,9 +1962,11 @@
private final static int REQUEST = 2;
private NetworkRequest somethingForNetwork(NetworkCapabilities need,
- NetworkCallbacks networkCallbacks, int timeoutSec, int action) {
+ NetworkCallbackListener networkCallbackListener, int timeoutSec, int action) {
NetworkRequest networkRequest = null;
- if (networkCallbacks == null) throw new IllegalArgumentException("null NetworkCallbacks");
+ if (networkCallbackListener == null) {
+ throw new IllegalArgumentException("null NetworkCallbackListener");
+ }
if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
try {
addCallbackListener();
@@ -1930,8 +1978,8 @@
timeoutSec, new Binder());
}
if (networkRequest != null) {
- synchronized(sNetworkCallbacks) {
- sNetworkCallbacks.put(networkRequest, networkCallbacks);
+ synchronized(sNetworkCallbackListener) {
+ sNetworkCallbackListener.put(networkRequest, networkCallbackListener);
}
}
} catch (RemoteException e) {}
@@ -1943,46 +1991,44 @@
* Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This {@link NetworkRequest} will live until released via
- * {@link releaseNetworkRequest} or the calling application exits.
- * Status of the request can be follwed by listening to the various
- * callbacks described in {@link NetworkCallbacks}. The {@link Network}
- * can be used by using the {@link bindSocketToNetwork},
- * {@link bindApplicationToNetwork} and {@link getAddrInfoOnNetwork} functions.
+ * {@link #releaseNetworkRequest} or the calling application exits.
+ * Status of the request can be followed by listening to the various
+ * callbacks described in {@link NetworkCallbackListener}. The {@link Network}
+ * can be used to direct traffic to the network.
*
* @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbacks The callbacks to be utilized for this request. Note
- * the callbacks can be shared by multiple requests and
- * the NetworkRequest token utilized to determine to which
- * request the callback relates.
+ * @param networkCallbackListener The {@link NetworkCallbackListener} to be utilized for this
+ * request. Note the callbacks can be shared by multiple
+ * requests and the NetworkRequest token utilized to
+ * determine to which request the callback relates.
* @return A {@link NetworkRequest} object identifying the request.
- * @hide
*/
public NetworkRequest requestNetwork(NetworkCapabilities need,
- NetworkCallbacks networkCallbacks) {
- return somethingForNetwork(need, networkCallbacks, 0, REQUEST);
+ NetworkCallbackListener networkCallbackListener) {
+ return somethingForNetwork(need, networkCallbackListener, 0, REQUEST);
}
/**
* Request a network to satisfy a set of {@link NetworkCapabilities}, limited
* by a timeout.
*
- * This function behaves identically, but if a suitable network is not found
- * within the given time (in Seconds) the {@link NetworkCallbacks#unavailable}
- * callback is called. The request must still be released normally by
- * calling {@link releaseNetworkRequest}.
+ * This function behaves identically to the non-timedout version, but if a suitable
+ * network is not found within the given time (in Seconds) the
+ * {@link NetworkCallbackListener#unavailable} callback is called. The request must
+ * still be released normally by calling {@link releaseNetworkRequest}.
* @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbacks The callbacks to be utilized for this request. Note
+ * @param networkCallbackListener The callbacks to be utilized for this request. Note
* the callbacks can be shared by multiple requests and
* the NetworkRequest token utilized to determine to which
* request the callback relates.
* @param timeoutSec The time in seconds to attempt looking for a suitable network
- * before {@link NetworkCallbacks#unavailable} is called.
+ * before {@link NetworkCallbackListener#unavailable} is called.
* @return A {@link NetworkRequest} object identifying the request.
* @hide
*/
public NetworkRequest requestNetwork(NetworkCapabilities need,
- NetworkCallbacks networkCallbacks, int timeoutSec) {
- return somethingForNetwork(need, networkCallbacks, timeoutSec, REQUEST);
+ NetworkCallbackListener networkCallbackListener, int timeoutSec) {
+ return somethingForNetwork(need, networkCallbackListener, timeoutSec, REQUEST);
}
/**
@@ -1993,36 +2039,52 @@
public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60;
/**
+ * The lookup key for a {@link Network} object included with the intent after
+ * succesfully finding a network for the applications request. Retrieve it with
+ * {@link android.content.Intent#getParcelableExtra(String)}.
+ */
+ public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
+
+ /**
+ * The lookup key for a {@link NetworkCapabilities} object included with the intent after
+ * succesfully finding a network for the applications request. Retrieve it with
+ * {@link android.content.Intent#getParcelableExtra(String)}.
+ */
+ public static final String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES =
+ "networkRequestNetworkCapabilities";
+
+
+ /**
* Request a network to satisfy a set of {@link NetworkCapabilities}.
*
- * This function behavies identically, but instead of {@link NetworkCallbacks}
- * a {@link PendingIntent} is used. This means the request may outlive the
- * calling application and get called back when a suitable network is found.
+ * This function behavies identically to the callback-equiped version, but instead
+ * of {@link NetworkCallbackListener} a {@link PendingIntent} is used. This means
+ * the request may outlive the calling application and get called back when a suitable
+ * network is found.
* <p>
* The operation is an Intent broadcast that goes to a broadcast receiver that
* you registered with {@link Context#registerReceiver} or through the
* <receiver> tag in an AndroidManifest.xml file
* <p>
* The operation Intent is delivered with two extras, a {@link Network} typed
- * extra called {@link EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
- * typed extra called {@link EXTRA_NETWORK_REQUEST_NETWORK_CAPABILTIES} containing
+ * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
+ * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES} containing
* the original requests parameters. It is important to create a new,
- * {@link NetworkCallbacks} based request before completing the processing of the
+ * {@link NetworkCallbackListener} based request before completing the processing of the
* Intent to reserve the network or it will be released shortly after the Intent
* is processed.
* <p>
* If there is already an request for this Intent registered (with the equality of
* two Intents defined by {@link Intent#filterEquals}), then it will be removed and
- * replace by this one, effectively releasing the previous {@link NetworkRequest}.
+ * replaced by this one, effectively releasing the previous {@link NetworkRequest}.
* <p>
- * The request may be released normally by calling {@link releaseNetworkRequest}.
+ * The request may be released normally by calling {@link #releaseNetworkRequest}.
*
- * @param need {@link NetworkCapabilties} required by this request.
+ * @param need {@link NetworkCapabilities} required by this request.
* @param operation Action to perform when the network is available (corresponds
- * to the {@link NetworkCallbacks#onAvailable} call. Typically
+ * to the {@link NetworkCallbackListener#onAvailable} call. Typically
* comes from {@link PendingIntent#getBroadcast}.
* @return A {@link NetworkRequest} object identifying the request.
- * @hide
*/
public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) {
try {
@@ -2035,28 +2097,27 @@
* Registers to receive notifications about all networks which satisfy the given
* {@link NetworkCapabilities}. The callbacks will continue to be called until
* either the application exits or the request is released using
- * {@link releaseNetworkRequest}.
+ * {@link #releaseNetworkRequest}.
*
* @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbacks The {@link NetworkCallbacks} to be called as suitable
+ * @param networkCallbackListener The {@link NetworkCallbackListener} to be called as suitable
* networks change state.
* @return A {@link NetworkRequest} object identifying the request.
- * @hide
*/
public NetworkRequest listenForNetwork(NetworkCapabilities need,
- NetworkCallbacks networkCallbacks) {
- return somethingForNetwork(need, networkCallbacks, 0, LISTEN);
+ NetworkCallbackListener networkCallbackListener) {
+ return somethingForNetwork(need, networkCallbackListener, 0, LISTEN);
}
/**
- * Releases a {NetworkRequest} generated either through a {@link requestNetwork}
- * or a {@link listenForNetwork} call. The {@link NetworkCallbacks} given in the
- * earlier call may continue receiving calls until the {@link NetworkCallbacks#onReleased}
- * function is called, signifiying the end of the request.
+ * Releases a {@link NetworkRequest} generated either through a {@link #requestNetwork}
+ * or a {@link #listenForNetwork} call. The {@link NetworkCallbackListener} given in the
+ * earlier call may continue receiving calls until the
+ * {@link NetworkCallbackListener#onReleased} function is called, signifying the end
+ * of the request.
*
* @param networkRequest The {@link NetworkRequest} generated by an earlier call to
- * {@link requestNetwork} or {@link listenForNetwork}.
- * @hide
+ * {@link #requestNetwork} or {@link #listenForNetwork}.
*/
public void releaseNetworkRequest(NetworkRequest networkRequest) {
if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest");
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index a725bec..d07c0b61 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -39,7 +39,8 @@
* <ul>
* <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
* The address must be unicast, as multicast addresses cannot be assigned to interfaces.
- * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties of the address.
+ * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties
+ * of the address.
* <li>Address scope: An integer defining the scope in which the address is unique (e.g.,
* {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}).
* <ul>
@@ -47,10 +48,9 @@
* When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and
* scope are optional. If they are not specified, the flags are set to zero, and the scope will be
* determined based on the IP address (e.g., link-local addresses will be created with a scope of
- * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, etc.) If they are
- * specified, they are not checked for validity.
+ * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE},
+ * etc.) If they are specified, they are not checked for validity.
*
- * @hide
*/
public class LinkAddress implements Parcelable {
/**
@@ -119,6 +119,10 @@
* the specified flags and scope. Flags and scope are not checked for validity.
* @param address The IP address.
* @param prefixLength The prefix length.
+ * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
+ * @param scope An integer defining the scope in which the address is unique (e.g.,
+ * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
+ * @hide
*/
public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
init(address, prefixLength, flags, scope);
@@ -129,6 +133,7 @@
* The flags are set to zero and the scope is determined from the address.
* @param address The IP address.
* @param prefixLength The prefix length.
+ * @hide
*/
public LinkAddress(InetAddress address, int prefixLength) {
this(address, prefixLength, 0, 0);
@@ -139,6 +144,7 @@
* Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
* The flags are set to zero and the scope is determined from the address.
* @param interfaceAddress The interface address.
+ * @hide
*/
public LinkAddress(InterfaceAddress interfaceAddress) {
this(interfaceAddress.getAddress(),
@@ -149,6 +155,7 @@
* Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
* "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
* @param string The string to parse.
+ * @hide
*/
public LinkAddress(String address) {
this(address, 0, 0);
@@ -161,6 +168,7 @@
* @param string The string to parse.
* @param flags The address flags.
* @param scope The address scope.
+ * @hide
*/
public LinkAddress(String address, int flags, int scope) {
InetAddress inetAddress = null;
@@ -220,9 +228,10 @@
}
/**
- * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} represent
- * the same address. Two LinkAddresses represent the same address if they have the same IP
- * address and prefix length, even if their properties are different.
+ * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress}
+ * represent the same address. Two {@code LinkAddresses} represent the same address
+ * if they have the same IP address and prefix length, even if their properties are
+ * different.
*
* @param other the {@code LinkAddress} to compare to.
* @return {@code true} if both objects have the same address and prefix length, {@code false}
@@ -233,28 +242,28 @@
}
/**
- * Returns the InetAddress of this address.
+ * Returns the {@link InetAddress} of this {@code LinkAddress}.
*/
public InetAddress getAddress() {
return address;
}
/**
- * Returns the prefix length of this address.
+ * Returns the prefix length of this {@code LinkAddress}.
*/
public int getNetworkPrefixLength() {
return prefixLength;
}
/**
- * Returns the flags of this address.
+ * Returns the flags of this {@code LinkAddress}.
*/
public int getFlags() {
return flags;
}
/**
- * Returns the scope of this address.
+ * Returns the scope of this {@code LinkAddress}.
*/
public int getScope() {
return scope;
@@ -262,6 +271,7 @@
/**
* Returns true if this {@code LinkAddress} is global scope and preferred.
+ * @hide
*/
public boolean isGlobalPreferred() {
return (scope == RT_SCOPE_UNIVERSE &&
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 489b8a5..3c36679 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -36,27 +36,12 @@
*
* A link represents a connection to a network.
* It may have multiple addresses and multiple gateways,
- * multiple dns servers but only one http proxy.
+ * multiple dns servers but only one http proxy and one
+ * network interface.
*
- * Because it's a single network, the dns's
- * are interchangeable and don't need associating with
- * particular addresses. The gateways similarly don't
- * need associating with particular addresses.
+ * Note that this is just a holder of data. Modifying it
+ * does not affect live networks.
*
- * A dual stack interface works fine in this model:
- * each address has it's own prefix length to describe
- * the local network. The dns servers all return
- * both v4 addresses and v6 addresses regardless of the
- * address family of the server itself (rfc4213) and we
- * don't care which is used. The gateways will be
- * selected based on the destination address and the
- * source address has no relavence.
- *
- * Links can also be stacked on top of each other.
- * This can be used, for example, to represent a tunnel
- * interface that runs on top of a physical interface.
- *
- * @hide
*/
public class LinkProperties implements Parcelable {
// The interface described by the network link.
@@ -73,6 +58,7 @@
private Hashtable<String, LinkProperties> mStackedLinks =
new Hashtable<String, LinkProperties>();
+ // @hide
public static class CompareResult<T> {
public Collection<T> removed = new ArrayList<T>();
public Collection<T> added = new ArrayList<T>();
@@ -91,7 +77,6 @@
public LinkProperties() {
}
- // copy constructor instead of clone
public LinkProperties(LinkProperties source) {
if (source != null) {
mIfaceName = source.getInterfaceName();
@@ -108,6 +93,12 @@
}
}
+ /**
+ * Sets the interface name for this link. All {@link RouteInfo} already set for this
+ * will have their interface changed to match this new value.
+ *
+ * @param iface The name of the network interface used for this link.
+ */
public void setInterfaceName(String iface) {
mIfaceName = iface;
ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
@@ -117,10 +108,16 @@
mRoutes = newRoutes;
}
+ /**
+ * Gets the interface name for this link. May be {@code null} if not set.
+ *
+ * @return The interface name set for this link or {@code null}.
+ */
public String getInterfaceName() {
return mIfaceName;
}
+ // @hide
public Collection<String> getAllInterfaceNames() {
Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
@@ -131,7 +128,14 @@
}
/**
- * Returns all the addresses on this link.
+ * Returns all the addresses on this link. We often think of a link having a single address,
+ * however, particularly with Ipv6 several addresses are typical. Note that the
+ * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
+ * prefix lengths for each address. This is a simplified utility alternative to
+ * {@link LinkProperties#getLinkAddresses}.
+ *
+ * @return An umodifiable {@link Collection} of {@link InetAddress} for this link.
+ * @hide
*/
public Collection<InetAddress> getAddresses() {
Collection<InetAddress> addresses = new ArrayList<InetAddress>();
@@ -143,6 +147,7 @@
/**
* Returns all the addresses on this link and all the links stacked above it.
+ * @hide
*/
public Collection<InetAddress> getAllAddresses() {
Collection<InetAddress> addresses = new ArrayList<InetAddress>();
@@ -165,7 +170,8 @@
}
/**
- * Adds a link address if it does not exist, or updates it if it does.
+ * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
+ * same address/prefix does not already exist. If it does exist it is replaced.
* @param address The {@code LinkAddress} to add.
* @return true if {@code address} was added or updated, false otherwise.
*/
@@ -189,9 +195,10 @@
}
/**
- * Removes a link address. Specifically, removes the link address, if any, for which
- * {@code isSameAddressAs(toRemove)} returns true.
- * @param address A {@code LinkAddress} specifying the address to remove.
+ * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches
+ * and {@link LinkAddress} with the same address and prefix.
+ *
+ * @param toRemove A {@link LinkAddress} specifying the address to remove.
* @return true if the address was removed, false if it did not exist.
*/
public boolean removeLinkAddress(LinkAddress toRemove) {
@@ -204,7 +211,10 @@
}
/**
- * Returns all the addresses on this link.
+ * Returns all the {@link LinkAddress} on this link. Typically a link will have
+ * one IPv4 address and one or more IPv6 addresses.
+ *
+ * @return An unmodifiable {@link Collection} of {@link LinkAddress} for this link.
*/
public Collection<LinkAddress> getLinkAddresses() {
return Collections.unmodifiableCollection(mLinkAddresses);
@@ -212,6 +222,7 @@
/**
* Returns all the addresses on this link and all the links stacked above it.
+ * @hide
*/
public Collection<LinkAddress> getAllLinkAddresses() {
Collection<LinkAddress> addresses = new ArrayList<LinkAddress>();
@@ -223,7 +234,11 @@
}
/**
- * Replaces the LinkAddresses on this link with the given collection of addresses.
+ * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
+ * the given {@link Collection} of {@link LinkAddress}.
+ *
+ * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
+ * object.
*/
public void setLinkAddresses(Collection<LinkAddress> addresses) {
mLinkAddresses.clear();
@@ -232,26 +247,64 @@
}
}
+ /**
+ * Adds the given {@link InetAddress} to the list of DNS servers.
+ *
+ * @param dns The {@link InetAddress} to add to the list of DNS servers.
+ */
public void addDns(InetAddress dns) {
if (dns != null) mDnses.add(dns);
}
+ /**
+ * Returns all the {@link LinkAddress} for DNS servers on this link.
+ *
+ * @return An umodifiable {@link Collection} of {@link InetAddress} for DNS servers on
+ * this link.
+ */
public Collection<InetAddress> getDnses() {
return Collections.unmodifiableCollection(mDnses);
}
- public String getDomains() {
- return mDomains;
- }
-
+ /**
+ * Sets the DNS domain search path used on this link.
+ *
+ * @param domains A {@link String} listing in priority order the comma separated
+ * domains to search when resolving host names on this link.
+ */
public void setDomains(String domains) {
mDomains = domains;
}
+ /**
+ * Get the DNS domains search path set for this link.
+ *
+ * @return A {@link String} containing the comma separated domains to search when resolving
+ * host names on this link.
+ */
+ public String getDomains() {
+ return mDomains;
+ }
+
+ /**
+ * Sets the Maximum Transmission Unit size to use on this link. This should not be used
+ * unless the system default (1500) is incorrect. Values less than 68 or greater than
+ * 10000 will be ignored.
+ *
+ * @param mtu The MTU to use for this link.
+ * @hide
+ */
public void setMtu(int mtu) {
mMtu = mtu;
}
+ /**
+ * Gets any non-default MTU size set for this link. Note that if the default is being used
+ * this will return 0.
+ *
+ * @return The mtu value set for this link.
+ * @hide
+ */
public int getMtu() {
return mMtu;
}
@@ -263,6 +316,14 @@
mIfaceName);
}
+ /**
+ * Adds a {@link RouteInfo} to this {@code LinkProperties}. If the {@link RouteInfo}
+ * had an interface name set and that differs from the interface set for this
+ * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The
+ * proper course is to add either un-named or properly named {@link RouteInfo}.
+ *
+ * @param route A {@link RouteInfo} to add to this object.
+ */
public void addRoute(RouteInfo route) {
if (route != null) {
String routeIface = route.getInterface();
@@ -276,7 +337,9 @@
}
/**
- * Returns all the routes on this link.
+ * Returns all the {@link RouteInfo} set on this link.
+ *
+ * @return An unmodifiable {@link Collection} of {@link RouteInfo} for this link.
*/
public Collection<RouteInfo> getRoutes() {
return Collections.unmodifiableCollection(mRoutes);
@@ -284,6 +347,7 @@
/**
* Returns all the routes on this link and all the links stacked above it.
+ * @hide
*/
public Collection<RouteInfo> getAllRoutes() {
Collection<RouteInfo> routes = new ArrayList();
@@ -294,9 +358,22 @@
return routes;
}
+ /**
+ * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
+ * Note that Http Proxies are only a hint - the system recommends their use, but it does
+ * not enforce it and applications may ignore them.
+ *
+ * @param proxy A {@link ProxyInfo} defining the Http Proxy to use on this link.
+ */
public void setHttpProxy(ProxyInfo proxy) {
mHttpProxy = proxy;
}
+
+ /**
+ * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
+ *
+ * @return The {@link ProxyInfo} set on this link
+ */
public ProxyInfo getHttpProxy() {
return mHttpProxy;
}
@@ -310,6 +387,7 @@
*
* @param link The link to add.
* @return true if the link was stacked, false otherwise.
+ * @hide
*/
public boolean addStackedLink(LinkProperties link) {
if (link != null && link.getInterfaceName() != null) {
@@ -327,6 +405,7 @@
*
* @param link The link to remove.
* @return true if the link was removed, false otherwise.
+ * @hide
*/
public boolean removeStackedLink(LinkProperties link) {
if (link != null && link.getInterfaceName() != null) {
@@ -338,6 +417,7 @@
/**
* Returns all the links stacked on top of this link.
+ * @hide
*/
public Collection<LinkProperties> getStackedLinks() {
Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
@@ -347,6 +427,9 @@
return Collections.unmodifiableCollection(stacked);
}
+ /**
+ * Clears this object to its initial state.
+ */
public void clear() {
mIfaceName = null;
mLinkAddresses.clear();
@@ -432,6 +515,7 @@
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
*/
public boolean isIdenticalInterfaceName(LinkProperties target) {
return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
@@ -442,6 +526,7 @@
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
*/
public boolean isIdenticalAddresses(LinkProperties target) {
Collection<InetAddress> targetAddresses = target.getAddresses();
@@ -455,6 +540,7 @@
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
*/
public boolean isIdenticalDnses(LinkProperties target) {
Collection<InetAddress> targetDnses = target.getDnses();
@@ -473,6 +559,7 @@
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
*/
public boolean isIdenticalRoutes(LinkProperties target) {
Collection<RouteInfo> targetRoutes = target.getRoutes();
@@ -485,6 +572,7 @@
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
*/
public boolean isIdenticalHttpProxy(LinkProperties target) {
return getHttpProxy() == null ? target.getHttpProxy() == null :
@@ -496,6 +584,7 @@
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
*/
public boolean isIdenticalStackedLinks(LinkProperties target) {
if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
@@ -516,6 +605,7 @@
*
* @param target LinkProperties to compare.
* @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
*/
public boolean isIdenticalMtu(LinkProperties target) {
return getMtu() == target.getMtu();
@@ -533,10 +623,6 @@
* 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
* 2. Worst case performance is O(n^2).
*
- * This method does not check that stacked interfaces are equal, because
- * stacked interfaces are not so much a property of the link as a
- * description of connections between links.
- *
* @param obj the object to be tested for equality.
* @return {@code true} if both objects are equal, {@code false} otherwise.
*/
@@ -546,7 +632,11 @@
if (!(obj instanceof LinkProperties)) return false;
LinkProperties target = (LinkProperties) obj;
-
+ /**
+ * This method does not check that stacked interfaces are equal, because
+ * stacked interfaces are not so much a property of the link as a
+ * description of connections between links.
+ */
return isIdenticalInterfaceName(target) &&
isIdenticalAddresses(target) &&
isIdenticalDnses(target) &&
@@ -562,6 +652,7 @@
*
* @param target a LinkProperties with the new list of addresses
* @return the differences between the addresses.
+ * @hide
*/
public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
/*
@@ -590,6 +681,7 @@
*
* @param target a LinkProperties with the new list of dns addresses
* @return the differences between the DNS addresses.
+ * @hide
*/
public CompareResult<InetAddress> compareDnses(LinkProperties target) {
/*
@@ -619,6 +711,7 @@
*
* @param target a LinkProperties with the new list of routes
* @return the differences between the routes.
+ * @hide
*/
public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
/*
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index ac1289b..e0d69e3 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -20,20 +20,34 @@
import android.os.Parcel;
import java.net.InetAddress;
+import java.net.Socket;
import java.net.UnknownHostException;
+import javax.net.SocketFactory;
/**
- * Identifies the Network.
- * @hide
+ * Identifies a {@code Network}. This is supplied to applications via
+ * {@link ConnectivityManager.NetworkCallbackListener} in response to
+ * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}.
+ * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
+ * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}.
*/
public class Network implements Parcelable {
+ /**
+ * @hide
+ */
public final int netId;
+ /**
+ * @hide
+ */
public Network(int netId) {
this.netId = netId;
}
+ /**
+ * @hide
+ */
public Network(Network that) {
this.netId = that.netId;
}
@@ -64,6 +78,45 @@
return InetAddress.getByNameOnNet(host, netId);
}
+ /**
+ * Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by
+ * this factory will have its traffic sent over this {@code Network}. Note that if this
+ * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the
+ * past or future will cease to work.
+ *
+ * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this
+ * {@code Network}.
+ */
+ public SocketFactory socketFactory() {
+ return null;
+ }
+
+ /**
+ * Binds the current process to this network. All sockets created in the future (and not
+ * explicitly bound via a bound {@link SocketFactory} (see {@link Network#socketFactory})
+ * will be bound to this network. Note that if this {@code Network} ever disconnects
+ * all sockets created in this way will cease to work. This is by design so an application
+ * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}.
+ */
+ public void bindProcess() {
+ }
+
+ /**
+ * A static utility method to return any {@code Network} currently bound by this process.
+ *
+ * @return {@code Network} to which this process is bound.
+ */
+ public static Network getProcessBoundNetwork() {
+ return null;
+ }
+
+ /**
+ * Clear any process specific {@code Network} binding. This reverts a call to
+ * {@link Network#bindProcess}.
+ */
+ public static void unbindProcess() {
+ }
+
// implement the Parcelable interface
public int describeContents() {
return 0;
@@ -84,4 +137,14 @@
return new Network[size];
}
};
+
+ public boolean equals(Object obj) {
+ if (obj instanceof Network == false) return false;
+ Network other = (Network)obj;
+ return this.netId == other.netId;
+ }
+
+ public int hashCode() {
+ return netId * 11;
+ }
}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 4b85398..c2b06a2 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -66,6 +66,7 @@
private AsyncChannel mAsyncChannel;
private final String LOG_TAG;
private static final boolean DBG = true;
+ private static final boolean VDBG = true;
// TODO - this class shouldn't cache data or it runs the risk of getting out of sync
// Make the API require each of these when any is updated so we have the data we need,
// without caching.
@@ -266,11 +267,14 @@
*/
private void evalScores() {
if (mConnectionRequested) {
+ if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size());
// already trying
return;
}
+ if (VDBG) log("evalScores!");
for (int i=0; i < mNetworkRequests.size(); i++) {
int score = mNetworkRequests.valueAt(i).score;
+ if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
if (score < mNetworkScore) {
// have a request that has a lower scored network servicing it
// (or no network) than we could provide, so lets connect!
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8005e5c..35274f1 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -30,13 +30,31 @@
import java.util.Set;
/**
- * A class representing the capabilities of a network
- * @hide
+ * This class represents the capabilities of a network. This is used both to specify
+ * needs to {@link ConnectivityManager} and when inspecting a network.
+ *
+ * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method
+ * of network selection. Rather than indicate a need for Wi-Fi because an application
+ * needs high bandwidth and risk obselence when a new, fast network appears (like LTE),
+ * the application should specify it needs high bandwidth. Similarly if an application
+ * needs an unmetered network for a bulk transfer it can specify that rather than assuming
+ * all cellular based connections are metered and all Wi-Fi based connections are not.
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
private static final boolean DBG = false;
+ public NetworkCapabilities() {
+ }
+
+ public NetworkCapabilities(NetworkCapabilities nc) {
+ if (nc != null) {
+ mNetworkCapabilities = nc.mNetworkCapabilities;
+ mTransportTypes = nc.mTransportTypes;
+ mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
+ mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
+ }
+ }
/**
* Represents the network's capabilities. If any are specified they will be satisfied
@@ -45,28 +63,99 @@
private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED);
/**
- * Values for NetworkCapabilities. Roughly matches/extends deprecated
- * ConnectivityManager TYPE_*
+ * Indicates this is a network that has the ability to reach the
+ * carrier's MMSC for sending and receiving MMS messages.
*/
public static final int NET_CAPABILITY_MMS = 0;
+
+ /**
+ * Indicates this is a network that has the ability to reach the carrier's
+ * SUPL server, used to retrieve GPS information.
+ */
public static final int NET_CAPABILITY_SUPL = 1;
+
+ /**
+ * Indicates this is a network that has the ability to reach the carrier's
+ * DUN or tethering gateway.
+ */
public static final int NET_CAPABILITY_DUN = 2;
+
+ /**
+ * Indicates this is a network that has the ability to reach the carrier's
+ * FOTA portal, used for over the air updates.
+ */
public static final int NET_CAPABILITY_FOTA = 3;
+
+ /**
+ * Indicates this is a network that has the ability to reach the carrier's
+ * IMS servers, used for network registration and signaling.
+ */
public static final int NET_CAPABILITY_IMS = 4;
+
+ /**
+ * Indicates this is a network that has the ability to reach the carrier's
+ * CBS servers, used for carrier specific services.
+ */
public static final int NET_CAPABILITY_CBS = 5;
+
+ /**
+ * Indicates this is a network that has the ability to reach a Wi-Fi direct
+ * peer.
+ */
public static final int NET_CAPABILITY_WIFI_P2P = 6;
+
+ /**
+ * Indicates this is a network that has the ability to reach a carrier's
+ * Initial Attach servers.
+ */
public static final int NET_CAPABILITY_IA = 7;
+
+ /**
+ * Indicates this is a network that has the ability to reach a carrier's
+ * RCS servers, used for Rich Communication Services.
+ */
public static final int NET_CAPABILITY_RCS = 8;
+
+ /**
+ * Indicates this is a network that has the ability to reach a carrier's
+ * XCAP servers, used for configuration and control.
+ */
public static final int NET_CAPABILITY_XCAP = 9;
+
+ /**
+ * Indicates this is a network that has the ability to reach a carrier's
+ * Emergency IMS servers, used for network signaling during emergency calls.
+ */
public static final int NET_CAPABILITY_EIMS = 10;
+
+ /**
+ * Indicates that this network is unmetered.
+ */
public static final int NET_CAPABILITY_NOT_METERED = 11;
+
+ /**
+ * Indicates that this network should be able to reach the internet.
+ */
public static final int NET_CAPABILITY_INTERNET = 12;
- /** Set by default */
+
+ /**
+ * Indicates that this network is available for general use. If this is not set
+ * applications should not attempt to communicate on this network. Note that this
+ * is simply informative and not enforcement - enforcement is handled via other means.
+ * Set by default.
+ */
public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED;
+ /**
+ * Adds the given capability to this {@code NetworkCapability} instance.
+ * Multiple capabilities may be applied sequentially. Note that when searching
+ * for a network to satisfy a request, all capabilities requested must be satisfied.
+ *
+ * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+ */
public void addNetworkCapability(int networkCapability) {
if (networkCapability < MIN_NET_CAPABILITY ||
networkCapability > MAX_NET_CAPABILITY) {
@@ -74,6 +163,12 @@
}
mNetworkCapabilities |= 1 << networkCapability;
}
+
+ /**
+ * Removes (if found) the given capability from this {@code NetworkCapability} instance.
+ *
+ * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+ */
public void removeNetworkCapability(int networkCapability) {
if (networkCapability < MIN_NET_CAPABILITY ||
networkCapability > MAX_NET_CAPABILITY) {
@@ -81,9 +176,23 @@
}
mNetworkCapabilities &= ~(1 << networkCapability);
}
+
+ /**
+ * Gets all the capabilities set on this {@code NetworkCapability} instance.
+ *
+ * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values
+ * for this instance.
+ */
public Collection<Integer> getNetworkCapabilities() {
return enumerateBits(mNetworkCapabilities);
}
+
+ /**
+ * Tests for the presence of a capabilitity on this instance.
+ *
+ * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
+ * @return {@code true} if set on this instance.
+ */
public boolean hasCapability(int networkCapability) {
if (networkCapability < MIN_NET_CAPABILITY ||
networkCapability > MAX_NET_CAPABILITY) {
@@ -124,31 +233,74 @@
private long mTransportTypes;
/**
- * Values for TransportType
+ * Indicates this network uses a Cellular transport.
*/
public static final int TRANSPORT_CELLULAR = 0;
+
+ /**
+ * Indicates this network uses a Wi-Fi transport.
+ */
public static final int TRANSPORT_WIFI = 1;
+
+ /**
+ * Indicates this network uses a Bluetooth transport.
+ */
public static final int TRANSPORT_BLUETOOTH = 2;
+
+ /**
+ * Indicates this network uses an Ethernet transport.
+ */
public static final int TRANSPORT_ETHERNET = 3;
private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET;
+ /**
+ * Adds the given transport type to this {@code NetworkCapability} instance.
+ * Multiple transports may be applied sequentially. Note that when searching
+ * for a network to satisfy a request, any listed in the request will satisfy the request.
+ * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
+ * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
+ * to be selected. This is logically different than
+ * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
+ *
+ * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
+ */
public void addTransportType(int transportType) {
if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
throw new IllegalArgumentException("TransportType out of range");
}
mTransportTypes |= 1 << transportType;
}
+
+ /**
+ * Removes (if found) the given transport from this {@code NetworkCapability} instance.
+ *
+ * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
+ */
public void removeTransportType(int transportType) {
if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
throw new IllegalArgumentException("TransportType out of range");
}
mTransportTypes &= ~(1 << transportType);
}
+
+ /**
+ * Gets all the transports set on this {@code NetworkCapability} instance.
+ *
+ * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values
+ * for this instance.
+ */
public Collection<Integer> getTransportTypes() {
return enumerateBits(mTransportTypes);
}
+
+ /**
+ * Tests for the presence of a transport on this instance.
+ *
+ * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for.
+ * @return {@code true} if set on this instance.
+ */
public boolean hasTransport(int transportType) {
if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
return false;
@@ -175,15 +327,58 @@
private int mLinkUpBandwidthKbps;
private int mLinkDownBandwidthKbps;
+ /**
+ * Sets the upstream bandwidth for this network in Kbps. This always only refers to
+ * the estimated first hop transport bandwidth.
+ * <p>
+ * Note that when used to request a network, this specifies the minimum acceptable.
+ * When received as the state of an existing network this specifies the typical
+ * first hop bandwidth expected. This is never measured, but rather is inferred
+ * from technology type and other link parameters. It could be used to differentiate
+ * between very slow 1xRTT cellular links and other faster networks or even between
+ * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
+ * fast backhauls and slow backhauls.
+ *
+ * @param upKbps the estimated first hop upstream (device to network) bandwidth.
+ */
public void setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
}
+
+ /**
+ * Retrieves the upstream bandwidth for this network in Kbps. This always only refers to
+ * the estimated first hop transport bandwidth.
+ *
+ * @return The estimated first hop upstream (device to network) bandwidth.
+ */
public int getLinkUpstreamBandwidthKbps() {
return mLinkUpBandwidthKbps;
}
+
+ /**
+ * Sets the downstream bandwidth for this network in Kbps. This always only refers to
+ * the estimated first hop transport bandwidth.
+ * <p>
+ * Note that when used to request a network, this specifies the minimum acceptable.
+ * When received as the state of an existing network this specifies the typical
+ * first hop bandwidth expected. This is never measured, but rather is inferred
+ * from technology type and other link parameters. It could be used to differentiate
+ * between very slow 1xRTT cellular links and other faster networks or even between
+ * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
+ * fast backhauls and slow backhauls.
+ *
+ * @param downKbps the estimated first hop downstream (network to device) bandwidth.
+ */
public void setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
}
+
+ /**
+ * Retrieves the downstream bandwidth for this network in Kbps. This always only refers to
+ * the estimated first hop transport bandwidth.
+ *
+ * @return The estimated first hop downstream (network to device) bandwidth.
+ */
public int getLinkDownstreamBandwidthKbps() {
return mLinkDownBandwidthKbps;
}
@@ -243,19 +438,6 @@
(mLinkDownBandwidthKbps * 13));
}
- public NetworkCapabilities() {
- }
-
- public NetworkCapabilities(NetworkCapabilities nc) {
- if (nc != null) {
- mNetworkCapabilities = nc.mNetworkCapabilities;
- mTransportTypes = nc.mTransportTypes;
- mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
- mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
- }
- }
-
- // Parcelable
public int describeContents() {
return 0;
}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index b3ae3f5..480cb057 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -22,11 +22,19 @@
import java.util.concurrent.atomic.AtomicInteger;
/**
- * @hide
+ * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork}
+ * or {@link ConnectivityManager#listenForNetwork}.
+ *
+ * This token records the {@link NetworkCapabilities} used to make the request and identifies
+ * the request. It should be used to release the request via
+ * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired.
*/
public class NetworkRequest implements Parcelable {
/**
- * The NetworkCapabilities that define this request
+ * The {@link NetworkCapabilities} that define this request. This should not be modified.
+ * The networkCapabilities of the request are set when
+ * {@link ConnectivityManager#requestNetwork} is called and the value is presented here
+ * as a convenient reminder of what was requested.
*/
public final NetworkCapabilities networkCapabilities;
@@ -34,7 +42,7 @@
* Identifies the request. NetworkRequests should only be constructed by
* the Framework and given out to applications as tokens to be used to identify
* the request.
- * TODO - make sure this input is checked whenever a NR is passed in a public API
+ * @hide
*/
public final int requestId;
@@ -45,31 +53,18 @@
*/
public final boolean needsBroadcasts;
- private static final AtomicInteger sNextRequestId = new AtomicInteger(1);
-
/**
* @hide
*/
- public NetworkRequest(NetworkCapabilities nc) {
- this(nc, false, sNextRequestId.getAndIncrement());
- }
-
- /**
- * @hide
- */
- public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) {
- this(nc, needsBroadcasts, sNextRequestId.getAndIncrement());
- }
-
- /**
- * @hide
- */
- private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
+ public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
requestId = rId;
networkCapabilities = nc;
this.needsBroadcasts = needsBroadcasts;
}
+ /**
+ * @hide
+ */
public NetworkRequest(NetworkRequest that) {
networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
requestId = that.requestId;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 1d051dd..ad8e4f7 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -25,22 +25,26 @@
import java.net.Inet6Address;
import java.util.Collection;
+import java.util.Objects;
/**
- * A simple container for route information.
+ * Represents a network route.
+ * <p>
+ * This is used both to describe static network configuration and live network
+ * configuration information.
*
- * In order to be used, a route must have a destination prefix and:
- *
- * - A gateway address (next-hop, for gatewayed routes), or
- * - An interface (for directly-connected routes), or
- * - Both a gateway and an interface.
- *
- * This class does not enforce these constraints because there is code that
- * uses RouteInfo objects to store directly-connected routes without interfaces.
- * Such objects cannot be used directly, but can be put into a LinkProperties
- * object which then specifies the interface.
- *
- * @hide
+ * A route contains three pieces of information:
+ * <ul>
+ * <li>a destination {@link LinkAddress} for directly-connected subnets. If this is
+ * {@code null} it indicates a default route of the address family (IPv4 or IPv6)
+ * implied by the gateway IP address.
+ * <li>a gateway {@link InetAddress} for default routes. If this is {@code null} it
+ * indicates a directly-connected route.
+ * <li>an interface (which may be unspecified).
+ * </ul>
+ * Either the destination or the gateway may be {@code null}, but not both. If the
+ * destination and gateway are both specified, they must be of the same address family
+ * (IPv4 or IPv6).
*/
public class RouteInfo implements Parcelable {
/**
@@ -67,10 +71,10 @@
*
* If destination is null, then gateway must be specified and the
* constructed route is either the IPv4 default route <code>0.0.0.0</code>
- * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
* route <code>::/0</code> if gateway is an instance of
* {@link Inet6Address}.
- *
+ * <p>
* destination and gateway may not both be null.
*
* @param destination the destination prefix
@@ -102,28 +106,64 @@
mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
+ if ((destination.getAddress() instanceof Inet4Address &&
+ (gateway instanceof Inet4Address == false)) ||
+ (destination.getAddress() instanceof Inet6Address &&
+ (gateway instanceof Inet6Address == false))) {
+ throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
+ }
mGateway = gateway;
mInterface = iface;
mIsDefault = isDefault();
mIsHost = isHost();
}
+ /**
+ * Constructs a {@code RouteInfo} object.
+ *
+ * If destination is null, then gateway must be specified and the
+ * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
+ * <p>
+ * Destination and gateway may not both be null.
+ *
+ * @param destination the destination address and prefix in a {@link LinkAddress}
+ * @param gateway the {@link InetAddress} to route packets through
+ */
public RouteInfo(LinkAddress destination, InetAddress gateway) {
this(destination, gateway, null);
}
+ /**
+ * Constructs a default {@code RouteInfo} object.
+ *
+ * @param gateway the {@link InetAddress} to route packets through
+ */
public RouteInfo(InetAddress gateway) {
this(null, gateway, null);
}
- public RouteInfo(LinkAddress host) {
- this(host, null, null);
+ /**
+ * Constructs a {@code RouteInfo} object representing a direct connected subnet.
+ *
+ * @param destination the {@link LinkAddress} describing the address and prefix
+ * length of the subnet.
+ */
+ public RouteInfo(LinkAddress destination) {
+ this(destination, null, null);
}
+ /**
+ * @hide
+ */
public static RouteInfo makeHostRoute(InetAddress host, String iface) {
return makeHostRoute(host, null, iface);
}
+ /**
+ * @hide
+ */
public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) {
if (host == null) return null;
@@ -153,31 +193,108 @@
return val;
}
-
+ /**
+ * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}.
+ *
+ * @return {@link LinkAddress} specifying the destination. This is never {@code null}.
+ */
public LinkAddress getDestination() {
return mDestination;
}
+ /**
+ * Retrieves the gateway or next hop {@link InetAddress} for this route.
+ *
+ * @return {@link InetAddress} specifying the gateway or next hop. This may be
+ & {@code null} for a directly-connected route."
+ */
public InetAddress getGateway() {
return mGateway;
}
+ /**
+ * Retrieves the interface used for this route if specified, else {@code null}.
+ *
+ * @return The name of the interface used for this route.
+ */
public String getInterface() {
return mInterface;
}
+ /**
+ * Indicates if this route is a default route (ie, has no destination specified).
+ *
+ * @return {@code true} if the destination has a prefix length of 0.
+ */
public boolean isDefaultRoute() {
return mIsDefault;
}
+ /**
+ * Indicates if this route is a host route (ie, matches only a single host address).
+ *
+ * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6.
+ * @hide
+ */
public boolean isHostRoute() {
return mIsHost;
}
+ /**
+ * Indicates if this route has a next hop ({@code true}) or is directly-connected
+ * ({@code false}).
+ *
+ * @return {@code true} if a gateway is specified
+ * @hide
+ */
public boolean hasGateway() {
return mHasGateway;
}
+ /**
+ * Determines whether the destination and prefix of this route includes the specified
+ * address.
+ *
+ * @param destination A {@link InetAddress} to test to see if it would match this route.
+ * @return {@code true} if the destination and prefix length cover the given address.
+ */
+ public boolean matches(InetAddress destination) {
+ if (destination == null) return false;
+
+ // match the route destination and destination with prefix length
+ InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
+ mDestination.getNetworkPrefixLength());
+
+ return mDestination.getAddress().equals(dstNet);
+ }
+
+ /**
+ * Find the route from a Collection of routes that best matches a given address.
+ * May return null if no routes are applicable.
+ * @param routes a Collection of RouteInfos to chose from
+ * @param dest the InetAddress your trying to get to
+ * @return the RouteInfo from the Collection that best fits the given address
+ *
+ * @hide
+ */
+ public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
+ if ((routes == null) || (dest == null)) return null;
+
+ RouteInfo bestRoute = null;
+ // pick a longest prefix match under same address type
+ for (RouteInfo route : routes) {
+ if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
+ if ((bestRoute != null) &&
+ (bestRoute.mDestination.getNetworkPrefixLength() >=
+ route.mDestination.getNetworkPrefixLength())) {
+ continue;
+ }
+ if (route.matches(dest)) bestRoute = route;
+ }
+ }
+ return bestRoute;
+ }
+
public String toString() {
String val = "";
if (mDestination != null) val = mDestination.toString();
@@ -185,10 +302,37 @@
return val;
}
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+
+ if (!(obj instanceof RouteInfo)) return false;
+
+ RouteInfo target = (RouteInfo) obj;
+
+ return Objects.equals(mDestination, target.getDestination()) &&
+ Objects.equals(mGateway, target.getGateway()) &&
+ Objects.equals(mInterface, target.getInterface());
+ }
+
+ public int hashCode() {
+ return (mDestination == null ? 0 : mDestination.hashCode() * 41)
+ + (mGateway == null ? 0 :mGateway.hashCode() * 47)
+ + (mInterface == null ? 0 :mInterface.hashCode() * 67)
+ + (mIsDefault ? 3 : 7);
+ }
+
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
public int describeContents() {
return 0;
}
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
public void writeToParcel(Parcel dest, int flags) {
if (mDestination == null) {
dest.writeByte((byte) 0);
@@ -208,38 +352,10 @@
dest.writeString(mInterface);
}
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
-
- if (!(obj instanceof RouteInfo)) return false;
-
- RouteInfo target = (RouteInfo) obj;
-
- boolean sameDestination = ( mDestination == null) ?
- target.getDestination() == null
- : mDestination.equals(target.getDestination());
-
- boolean sameAddress = (mGateway == null) ?
- target.getGateway() == null
- : mGateway.equals(target.getGateway());
-
- boolean sameInterface = (mInterface == null) ?
- target.getInterface() == null
- : mInterface.equals(target.getInterface());
-
- return sameDestination && sameAddress && sameInterface
- && mIsDefault == target.mIsDefault;
- }
-
- @Override
- public int hashCode() {
- return (mDestination == null ? 0 : mDestination.hashCode() * 41)
- + (mGateway == null ? 0 :mGateway.hashCode() * 47)
- + (mInterface == null ? 0 :mInterface.hashCode() * 67)
- + (mIsDefault ? 3 : 7);
- }
-
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
public static final Creator<RouteInfo> CREATOR =
new Creator<RouteInfo>() {
public RouteInfo createFromParcel(Parcel in) {
@@ -279,39 +395,4 @@
return new RouteInfo[size];
}
};
-
- protected boolean matches(InetAddress destination) {
- if (destination == null) return false;
-
- // match the route destination and destination with prefix length
- InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
- mDestination.getNetworkPrefixLength());
-
- return mDestination.getAddress().equals(dstNet);
- }
-
- /**
- * Find the route from a Collection of routes that best matches a given address.
- * May return null if no routes are applicable.
- * @param routes a Collection of RouteInfos to chose from
- * @param dest the InetAddress your trying to get to
- * @return the RouteInfo from the Collection that best fits the given address
- */
- public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
- if ((routes == null) || (dest == null)) return null;
-
- RouteInfo bestRoute = null;
- // pick a longest prefix match under same address type
- for (RouteInfo route : routes) {
- if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
- if ((bestRoute != null) &&
- (bestRoute.mDestination.getNetworkPrefixLength() >=
- route.mDestination.getNetworkPrefixLength())) {
- continue;
- }
- if (route.matches(dest)) bestRoute = route;
- }
- }
- return bestRoute;
- }
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cf0caed..af45fa0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -531,7 +531,8 @@
public final static class HistoryItem implements Parcelable {
public HistoryItem next;
-
+
+ // The time of this event in milliseconds, as per SystemClock.elapsedRealtime().
public long time;
public static final byte CMD_UPDATE = 0; // These can be written as deltas
@@ -645,7 +646,7 @@
public int eventCode;
public HistoryTag eventTag;
- // Only set for CMD_CURRENT_TIME.
+ // Only set for CMD_CURRENT_TIME or CMD_RESET, as per System.currentTimeMillis().
public long currentTime;
// Meta-data when reading.
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 5c8c8e9..ad940c6 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -621,8 +621,9 @@
* Registers a listener.
*
* @see OnActivityStopListener
+ * @hide
*/
- void registerOnActivityStopListener(OnActivityStopListener listener) {
+ public void registerOnActivityStopListener(OnActivityStopListener listener) {
synchronized (this) {
if (mActivityStopListeners == null) {
mActivityStopListeners = new ArrayList<OnActivityStopListener>();
@@ -638,8 +639,9 @@
* Unregisters a listener.
*
* @see OnActivityStopListener
+ * @hide
*/
- void unregisterOnActivityStopListener(OnActivityStopListener listener) {
+ public void unregisterOnActivityStopListener(OnActivityStopListener listener) {
synchronized (this) {
if (mActivityStopListeners != null) {
mActivityStopListeners.remove(listener);
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
new file mode 100644
index 0000000..d2d6ade
--- /dev/null
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -0,0 +1,248 @@
+/*
+ * 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.preference;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.preference.VolumePreference.VolumeStore;
+import android.provider.Settings;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+
+/**
+ * Turns a {@link SeekBar} into a volume control.
+ * @hide
+ */
+public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
+
+ public interface Callback {
+ void onSampleStarting(SeekBarVolumizer sbv);
+ }
+
+ private Context mContext;
+ private Handler mHandler;
+ private final Callback mCallback;
+
+ private AudioManager mAudioManager;
+ private int mStreamType;
+ private int mOriginalStreamVolume;
+ private Ringtone mRingtone;
+
+ private int mLastProgress = -1;
+ private SeekBar mSeekBar;
+ private int mVolumeBeforeMute = -1;
+
+ private static final int MSG_SET_STREAM_VOLUME = 0;
+ private static final int MSG_START_SAMPLE = 1;
+ private static final int MSG_STOP_SAMPLE = 2;
+ private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
+
+ private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ if (mSeekBar != null && mAudioManager != null) {
+ int volume = mAudioManager.getStreamVolume(mStreamType);
+ mSeekBar.setProgress(volume);
+ }
+ }
+ };
+
+ public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType, Uri defaultUri,
+ Callback callback) {
+ mContext = context;
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mStreamType = streamType;
+ mSeekBar = seekBar;
+
+ HandlerThread thread = new HandlerThread(VolumePreference.TAG + ".CallbackHandler");
+ thread.start();
+ mHandler = new Handler(thread.getLooper(), this);
+ mCallback = callback;
+
+ initSeekBar(seekBar, defaultUri);
+ }
+
+ private void initSeekBar(SeekBar seekBar, Uri defaultUri) {
+ seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
+ mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
+ seekBar.setProgress(mOriginalStreamVolume);
+ seekBar.setOnSeekBarChangeListener(this);
+
+ mContext.getContentResolver().registerContentObserver(
+ System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
+ false, mVolumeObserver);
+
+ if (defaultUri == null) {
+ if (mStreamType == AudioManager.STREAM_RING) {
+ defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
+ } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
+ defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+ } else {
+ defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
+ }
+ }
+
+ mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
+
+ if (mRingtone != null) {
+ mRingtone.setStreamType(mStreamType);
+ }
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_STREAM_VOLUME:
+ mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+ break;
+ case MSG_START_SAMPLE:
+ onStartSample();
+ break;
+ case MSG_STOP_SAMPLE:
+ onStopSample();
+ break;
+ default:
+ Log.e(VolumePreference.TAG, "invalid SeekBarVolumizer message: "+msg.what);
+ }
+ return true;
+ }
+
+ private void postStartSample() {
+ mHandler.removeMessages(MSG_START_SAMPLE);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
+ isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
+ }
+
+ private void onStartSample() {
+ if (!isSamplePlaying()) {
+ if (mCallback != null) {
+ mCallback.onSampleStarting(this);
+ }
+ if (mRingtone != null) {
+ mRingtone.play();
+ }
+ }
+ }
+
+ void postStopSample() {
+ // remove pending delayed start messages
+ mHandler.removeMessages(MSG_START_SAMPLE);
+ mHandler.removeMessages(MSG_STOP_SAMPLE);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE));
+ }
+
+ private void onStopSample() {
+ if (mRingtone != null) {
+ mRingtone.stop();
+ }
+ }
+
+ public void stop() {
+ postStopSample();
+ mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
+ mSeekBar.setOnSeekBarChangeListener(null);
+ }
+
+ public void revertVolume() {
+ mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
+ }
+
+ public void onProgressChanged(SeekBar seekBar, int progress,
+ boolean fromTouch) {
+ if (!fromTouch) {
+ return;
+ }
+
+ postSetVolume(progress);
+ }
+
+ void postSetVolume(int progress) {
+ // Do the volume changing separately to give responsive UI
+ mLastProgress = progress;
+ mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
+ }
+
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ postStartSample();
+ }
+
+ public boolean isSamplePlaying() {
+ return mRingtone != null && mRingtone.isPlaying();
+ }
+
+ public void startSample() {
+ postStartSample();
+ }
+
+ public void stopSample() {
+ postStopSample();
+ }
+
+ public SeekBar getSeekBar() {
+ return mSeekBar;
+ }
+
+ public void changeVolumeBy(int amount) {
+ mSeekBar.incrementProgressBy(amount);
+ postSetVolume(mSeekBar.getProgress());
+ postStartSample();
+ mVolumeBeforeMute = -1;
+ }
+
+ public void muteVolume() {
+ if (mVolumeBeforeMute != -1) {
+ mSeekBar.setProgress(mVolumeBeforeMute);
+ postSetVolume(mVolumeBeforeMute);
+ postStartSample();
+ mVolumeBeforeMute = -1;
+ } else {
+ mVolumeBeforeMute = mSeekBar.getProgress();
+ mSeekBar.setProgress(0);
+ postStopSample();
+ postSetVolume(0);
+ }
+ }
+
+ public void onSaveInstanceState(VolumeStore volumeStore) {
+ if (mLastProgress >= 0) {
+ volumeStore.volume = mLastProgress;
+ volumeStore.originalVolume = mOriginalStreamVolume;
+ }
+ }
+
+ public void onRestoreInstanceState(VolumeStore volumeStore) {
+ if (volumeStore.volume != -1) {
+ mOriginalStreamVolume = volumeStore.originalVolume;
+ mLastProgress = volumeStore.volume;
+ postSetVolume(mLastProgress);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 39cb826..171e5c3 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -19,32 +19,20 @@
import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
-import android.provider.Settings;
-import android.provider.Settings.System;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
/**
* @hide
*/
public class VolumePreference extends SeekBarDialogPreference implements
- PreferenceManager.OnActivityStopListener, View.OnKeyListener {
+ PreferenceManager.OnActivityStopListener, View.OnKeyListener, SeekBarVolumizer.Callback {
- private static final String TAG = "VolumePreference";
+ static final String TAG = "VolumePreference";
private int mStreamType;
@@ -78,7 +66,7 @@
super.onBindDialogView(view);
final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
- mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
+ mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType, null, this);
getPreferenceManager().registerOnActivityStopListener(this);
@@ -152,7 +140,8 @@
}
- protected void onSampleStarting(SeekBarVolumizer volumizer) {
+ @Override
+ public void onSampleStarting(SeekBarVolumizer volumizer) {
if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
mSeekBarVolumizer.stopSample();
}
@@ -228,213 +217,4 @@
}
};
}
-
- /**
- * Turns a {@link SeekBar} into a volume control.
- */
- public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
-
- private Context mContext;
- private Handler mHandler;
-
- private AudioManager mAudioManager;
- private int mStreamType;
- private int mOriginalStreamVolume;
- private Ringtone mRingtone;
-
- private int mLastProgress = -1;
- private SeekBar mSeekBar;
- private int mVolumeBeforeMute = -1;
-
- private static final int MSG_SET_STREAM_VOLUME = 0;
- private static final int MSG_START_SAMPLE = 1;
- private static final int MSG_STOP_SAMPLE = 2;
- private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
-
- private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- if (mSeekBar != null && mAudioManager != null) {
- int volume = mAudioManager.getStreamVolume(mStreamType);
- mSeekBar.setProgress(volume);
- }
- }
- };
-
- public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) {
- this(context, seekBar, streamType, null);
- }
-
- public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType, Uri defaultUri) {
- mContext = context;
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- mStreamType = streamType;
- mSeekBar = seekBar;
-
- HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
- thread.start();
- mHandler = new Handler(thread.getLooper(), this);
-
- initSeekBar(seekBar, defaultUri);
- }
-
- private void initSeekBar(SeekBar seekBar, Uri defaultUri) {
- seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
- mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
- seekBar.setProgress(mOriginalStreamVolume);
- seekBar.setOnSeekBarChangeListener(this);
-
- mContext.getContentResolver().registerContentObserver(
- System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
- false, mVolumeObserver);
-
- if (defaultUri == null) {
- if (mStreamType == AudioManager.STREAM_RING) {
- defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
- } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
- defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
- } else {
- defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
- }
- }
-
- mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
-
- if (mRingtone != null) {
- mRingtone.setStreamType(mStreamType);
- }
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SET_STREAM_VOLUME:
- mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
- break;
- case MSG_START_SAMPLE:
- onStartSample();
- break;
- case MSG_STOP_SAMPLE:
- onStopSample();
- break;
- default:
- Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
- }
- return true;
- }
-
- private void postStartSample() {
- mHandler.removeMessages(MSG_START_SAMPLE);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
- isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
- }
-
- private void onStartSample() {
- if (!isSamplePlaying()) {
- onSampleStarting(this);
- if (mRingtone != null) {
- mRingtone.play();
- }
- }
- }
-
- private void postStopSample() {
- // remove pending delayed start messages
- mHandler.removeMessages(MSG_START_SAMPLE);
- mHandler.removeMessages(MSG_STOP_SAMPLE);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE));
- }
-
- private void onStopSample() {
- if (mRingtone != null) {
- mRingtone.stop();
- }
- }
-
- public void stop() {
- postStopSample();
- mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
- mSeekBar.setOnSeekBarChangeListener(null);
- }
-
- public void revertVolume() {
- mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
- }
-
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromTouch) {
- if (!fromTouch) {
- return;
- }
-
- postSetVolume(progress);
- }
-
- void postSetVolume(int progress) {
- // Do the volume changing separately to give responsive UI
- mLastProgress = progress;
- mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
- }
-
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- public void onStopTrackingTouch(SeekBar seekBar) {
- postStartSample();
- }
-
- public boolean isSamplePlaying() {
- return mRingtone != null && mRingtone.isPlaying();
- }
-
- public void startSample() {
- postStartSample();
- }
-
- public void stopSample() {
- postStopSample();
- }
-
- public SeekBar getSeekBar() {
- return mSeekBar;
- }
-
- public void changeVolumeBy(int amount) {
- mSeekBar.incrementProgressBy(amount);
- postSetVolume(mSeekBar.getProgress());
- postStartSample();
- mVolumeBeforeMute = -1;
- }
-
- public void muteVolume() {
- if (mVolumeBeforeMute != -1) {
- mSeekBar.setProgress(mVolumeBeforeMute);
- postSetVolume(mVolumeBeforeMute);
- postStartSample();
- mVolumeBeforeMute = -1;
- } else {
- mVolumeBeforeMute = mSeekBar.getProgress();
- mSeekBar.setProgress(0);
- postStopSample();
- postSetVolume(0);
- }
- }
-
- public void onSaveInstanceState(VolumeStore volumeStore) {
- if (mLastProgress >= 0) {
- volumeStore.volume = mLastProgress;
- volumeStore.originalVolume = mOriginalStreamVolume;
- }
- }
-
- public void onRestoreInstanceState(VolumeStore volumeStore) {
- if (volumeStore.volume != -1) {
- mOriginalStreamVolume = volumeStore.originalVolume;
- mLastProgress = volumeStore.volume;
- postSetVolume(mLastProgress);
- }
- }
- }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d09bb88..e896063 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -773,13 +773,24 @@
* Activity Action: Show Device Name Settings.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard
- * against ithis.
+ * against this.
*
* @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String DEVICE_NAME_SETTINGS = "android.settings.DEVICE_NAME";
+ /**
+ * Activity Action: Show pairing settings.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you safeguard
+ * against this.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_PAIRING_SETTINGS = "android.settings.PAIRING_SETTINGS";
+
// End of Intent actions for Settings
/**
@@ -2900,6 +2911,7 @@
MOVED_TO_GLOBAL.add(Settings.Global.SET_GLOBAL_HTTP_PROXY);
MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_DNS_SERVER);
MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_NETWORK_MODE);
+ MOVED_TO_GLOBAL.add(Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
}
/** @hide */
@@ -4544,6 +4556,12 @@
public static final String PAYMENT_SERVICE_SEARCH_URI = "payment_service_search_uri";
/**
+ * If enabled, intercepted notifications will be displayed (not suppressed) in zen mode.
+ * @hide
+ */
+ public static final String DISPLAY_INTERCEPTED_NOTIFICATIONS = "display_intercepted_notifications";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -5330,6 +5348,13 @@
*/
public static final String USE_GOOGLE_MAIL = "use_google_mail";
+ /**
+ * Webview Data reduction proxy key.
+ * @hide
+ */
+ public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
+ "webview_data_reduction_proxy_key";
+
/**
* Whether Wifi display is enabled/disabled
* 0=disabled. 1=enabled.
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a94f45a..e2e9ff4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -16,9 +16,11 @@
package android.service.notification;
+import android.annotation.PrivateApi;
import android.annotation.SdkConstant;
import android.app.INotificationManager;
import android.app.Service;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
@@ -26,9 +28,6 @@
import android.os.ServiceManager;
import android.util.Log;
-import java.util.Comparator;
-import java.util.HashMap;
-
/**
* A service that receives calls from the system when new notifications are posted or removed.
* <p>To extend this class, you must declare the service in your manifest file with
@@ -53,6 +52,9 @@
private INotificationManager mNoMan;
+ /** Only valid after a successful call to (@link registerAsService}. */
+ private int mCurrentUser;
+
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -267,6 +269,42 @@
return true;
}
+ /**
+ * Directly register this service with the Notification Manager.
+ *
+ * <p>Only system services may use this call. It will fail for non-system callers.
+ * Apps should ask the user to add their listener in Settings.
+ *
+ * @param componentName the component that will consume the notification information
+ * @param currentUser the user to use as the stream filter
+ * @hide
+ */
+ @PrivateApi
+ public void registerAsSystemService(ComponentName componentName, int currentUser)
+ throws RemoteException {
+ if (mWrapper == null) {
+ mWrapper = new INotificationListenerWrapper();
+ }
+ INotificationManager noMan = getNotificationInterface();
+ noMan.registerListener(mWrapper, componentName, currentUser);
+ mCurrentUser = currentUser;
+ }
+
+ /**
+ * Directly unregister this service from the Notification Manager.
+ *
+ * <P>This method will fail for listeners that were not registered
+ * with (@link registerAsService).
+ * @hide
+ */
+ @PrivateApi
+ public void unregisterAsSystemService() throws RemoteException {
+ if (mWrapper != null) {
+ INotificationManager noMan = getNotificationInterface();
+ noMan.unregisterListener(mWrapper, mCurrentUser);
+ }
+ }
+
private class INotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(StatusBarNotification sbn,
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index bb40eec..98f70f40 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -16,12 +16,17 @@
package android.service.trust;
+import android.Manifest;
import android.annotation.SdkConstant;
import android.app.Service;
+import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.Log;
import android.util.Slog;
/**
@@ -83,6 +88,22 @@
};
};
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ ComponentName component = new ComponentName(this, getClass());
+ try {
+ ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
+ if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
+ throw new IllegalStateException(component.flattenToShortString()
+ + " is not declared with the permission "
+ + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
+ }
+ }
+
/**
* Called when the user attempted to authenticate on the device.
*
diff --git a/core/java/android/service/voice/package.html b/core/java/android/service/voice/package.html
new file mode 100644
index 0000000..1c9bf9d
--- /dev/null
+++ b/core/java/android/service/voice/package.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ {@hide}
+</body>
+</html>
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 10e2073..85f702b 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -25,7 +25,10 @@
import android.media.AudioManager;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.speech.tts.ITextToSpeechCallback;
@@ -86,6 +89,8 @@
private HashMap<String, Pair<UtteranceId, RequestCallbacks>> mCallbacks;
// Guarded by mLock
+ private InternalHandler mMainHandler = new InternalHandler();
+
/** Common voices parameters */
public static final class Params {
private Params() {}
@@ -300,6 +305,8 @@
/**
* Interface definition of callbacks that are called when the client is
* connected or disconnected from the TTS service.
+ *
+ * The callbacks specified in this method will be called on the UI thread.
*/
public static interface ConnectionCallbacks {
/**
@@ -325,6 +332,9 @@
* with the speech service (e.g. a crash or resource problem causes it to be killed by the
* system). When called, all requests have been canceled and no outstanding listeners will
* be executed. Applications should disable UI components that require the service.
+ *
+ * When the service is working again, the client will receive a callback to the
+ * {@link #onConnectionSuccess()} method.
*/
public void onServiceDisconnected();
@@ -688,7 +698,8 @@
synchronized (mLock) {
mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(),
voicesInfo);
- mConnectionCallbacks.onEngineStatusChange(mEngineStatus);
+ mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED,
+ mEngineStatus).sendToTarget();
}
}
};
@@ -753,9 +764,11 @@
Log.i(TAG, "Asked to disconnect from " + name);
synchronized(mLock) {
+ mEstablished = false;
+ mService = null;
stopSetupConnectionTask();
}
- mConnectionCallbacks.onServiceDisconnected();
+ mMainHandler.obtainMessage(InternalHandler.WHAT_SERVICE_DISCONNECTED).sendToTarget();
}
private void startSetupConnectionTask(ComponentName name) {
@@ -830,9 +843,11 @@
private boolean runAction(Action action) {
synchronized (mLock) {
if (mServiceConnection == null) {
+ Log.w(TAG, action.getName() + " failed: not bound to TTS engine");
return false;
}
if (!mServiceConnection.isEstablished()) {
+ Log.w(TAG, action.getName() + " failed: not fully bound to TTS engine");
return false;
}
mServiceConnection.runAction(action);
@@ -1044,4 +1059,21 @@
}
});
}
+
+ class InternalHandler extends Handler {
+ final static int WHAT_ENGINE_STATUS_CHANGED = 1;
+ final static int WHAT_SERVICE_DISCONNECTED = 2;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case WHAT_ENGINE_STATUS_CHANGED:
+ mConnectionCallbacks.onEngineStatusChange((EngineStatus) msg.obj);
+ return;
+ case WHAT_SERVICE_DISCONNECTED:
+ mConnectionCallbacks.onServiceDisconnected();
+ return;
+ }
+ }
+ }
}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index d7c51fc..6b899d9 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -255,7 +255,8 @@
// V2 to V1 interface adapter. This allows using V2 client interface on V1-only services.
Bundle defaultParams = new Bundle();
defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_PITCH, 1.0f);
- defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, -1.0f);
+ // Speech speed <= 0 makes it use a system wide setting
+ defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, 0.0f);
// Enumerate all locales and check if they are available
ArrayList<VoiceInfo> voicesInfo = new ArrayList<VoiceInfo>();
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/util/Rational.java
similarity index 92%
rename from core/java/android/hardware/camera2/Rational.java
rename to core/java/android/util/Rational.java
index 693ee2b..8d4c67f 100644
--- a/core/java/android/hardware/camera2/Rational.java
+++ b/core/java/android/util/Rational.java
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.camera2;
+package android.util;
/**
- * The rational data type used by CameraMetadata keys. Contains a pair of ints representing the
- * numerator and denominator of a Rational number. This type is immutable.
+ * <p>An immutable data type representation a rational number.</p>
+ *
+ * <p>Contains a pair of {@code int}s representing the numerator and denominator of a
+ * Rational number. </p>
*/
public final class Rational {
private final int mNumerator;
@@ -30,7 +32,9 @@
* is always positive.</p>
*
* <p>A rational value with a 0-denominator may be constructed, but will have similar semantics
- * as float NaN and INF values. The int getter functions return 0 in this case.</p>
+ * as float {@code NaN} and {@code INF} values. For {@code NaN},
+ * both {@link #getNumerator} and {@link #getDenominator} functions will return 0. For
+ * positive or negative {@code INF}, only the {@link #getDenominator} will return 0.</p>
*
* @param numerator the numerator of the rational
* @param denominator the denominator of the rational
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 7b49006..9601a8d 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1220,10 +1220,6 @@
}
private RenderNode buildDisplayList(View view, HardwareCanvas canvas) {
- if (mDrawDelta <= 0) {
- return view.mRenderNode;
- }
-
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
== View.PFLAG_INVALIDATED;
view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 852fce5..b8e1b89 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -639,8 +639,13 @@
* Wakes up the device. Behaves somewhat like {@link #KEYCODE_POWER} but it
* has no effect if the device is already awake. */
public static final int KEYCODE_WAKEUP = 224;
+ /** Key code constant: Pairing key.
+ * Initiates peripheral pairing mode. Useful for pairing remote control
+ * devices or game controllers, especially if no other input mode is
+ * available. */
+ public static final int KEYCODE_PAIRING = 225;
- private static final int LAST_KEYCODE = KEYCODE_WAKEUP;
+ private static final int LAST_KEYCODE = KEYCODE_PAIRING;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index f14e73f..c1a4fee 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -16,6 +16,7 @@
package android.view;
+import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
@@ -28,12 +29,12 @@
import com.android.internal.view.animation.NativeInterpolatorFactory;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
/**
* @hide
*/
-public final class RenderNodeAnimator {
-
+public final class RenderNodeAnimator extends Animator {
// Keep in sync with enum RenderProperty in Animator.h
public static final int TRANSLATION_X = 0;
public static final int TRANSLATION_Y = 1;
@@ -50,6 +51,11 @@
// Keep in sync with enum PaintFields in Animator.h
public static final int PAINT_STROKE_WIDTH = 0;
+
+ /**
+ * Field for the Paint alpha channel, which should be specified as a value
+ * between 0 and 255.
+ */
public static final int PAINT_ALPHA = 1;
// ViewPropertyAnimator uses a mask for its values, we need to remap them
@@ -74,8 +80,11 @@
private VirtualRefBasePtr mNativePtr;
private RenderNode mTarget;
+ private View mViewTarget;
private TimeInterpolator mInterpolator;
+
private boolean mStarted = false;
+ private boolean mFinished = false;
public int mapViewPropertyToRenderProperty(int viewProperty) {
return sViewPropertyAnimatorMap.get(viewProperty);
@@ -92,6 +101,14 @@
property.getNativeContainer(), finalValue));
}
+ /**
+ * Creates a new render node animator for a field on a Paint property.
+ *
+ * @param property The paint property to target
+ * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
+ * {@link #PAINT_STROKE_WIDTH}
+ * @param finalValue The target value for the property
+ */
public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
init(nCreateCanvasPropertyPaintAnimator(
new WeakReference<RenderNodeAnimator>(this),
@@ -115,56 +132,139 @@
if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) {
ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
} else {
- int duration = nGetDuration(mNativePtr.get());
+ long duration = nGetDuration(mNativePtr.get());
ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
}
nSetInterpolator(mNativePtr.get(), ni);
}
- private void start(RenderNode node) {
+ @Override
+ public void start() {
+ if (mTarget == null) {
+ throw new IllegalStateException("Missing target!");
+ }
+
if (mStarted) {
throw new IllegalStateException("Already started!");
}
+
mStarted = true;
applyInterpolator();
- mTarget = node;
mTarget.addAnimator(this);
+
+ final ArrayList<AnimatorListener> listeners = getListeners();
+ final int numListeners = listeners == null ? 0 : listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ listeners.get(i).onAnimationStart(this);
+ }
+
+ if (mViewTarget != null) {
+ // Kick off a frame to start the process
+ mViewTarget.invalidateViewProperty(true, false);
+ }
}
- public void start(View target) {
- start(target.mRenderNode);
- // Kick off a frame to start the process
- target.invalidateViewProperty(true, false);
+ @Override
+ public void cancel() {
+ mTarget.removeAnimator(this);
+
+ final ArrayList<AnimatorListener> listeners = getListeners();
+ final int numListeners = listeners == null ? 0 : listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ listeners.get(i).onAnimationCancel(this);
+ }
}
- public void start(Canvas canvas) {
+ @Override
+ public void end() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void pause() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void resume() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTarget(View view) {
+ mViewTarget = view;
+ mTarget = view.mRenderNode;
+ }
+
+ public void setTarget(Canvas canvas) {
if (!(canvas instanceof GLES20RecordingCanvas)) {
throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
}
- GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
- start(recordingCanvas.mNode);
+
+ final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+ setTarget(recordingCanvas.mNode);
}
- public void cancel() {
- mTarget.removeAnimator(this);
+ public void setTarget(RenderNode node) {
+ mViewTarget = null;
+ mTarget = node;
}
- public void setDuration(int duration) {
+ public RenderNode getTarget() {
+ return mTarget;
+ }
+
+ @Override
+ public void setStartDelay(long startDelay) {
+ checkMutable();
+ nSetStartDelay(mNativePtr.get(), startDelay);
+ }
+
+ @Override
+ public long getStartDelay() {
+ return nGetStartDelay(mNativePtr.get());
+ }
+
+ @Override
+ public RenderNodeAnimator setDuration(long duration) {
checkMutable();
nSetDuration(mNativePtr.get(), duration);
+ return this;
}
+ @Override
+ public long getDuration() {
+ return nGetDuration(mNativePtr.get());
+ }
+
+ @Override
+ public boolean isRunning() {
+ return mStarted && !mFinished;
+ }
+
+ @Override
public void setInterpolator(TimeInterpolator interpolator) {
checkMutable();
mInterpolator = interpolator;
}
- long getNativeAnimator() {
- return mNativePtr.get();
+ @Override
+ public TimeInterpolator getInterpolator() {
+ return mInterpolator;
}
private void onFinished() {
+ mFinished = true;
mTarget.removeAnimator(this);
+
+ final ArrayList<AnimatorListener> listeners = getListeners();
+ final int numListeners = listeners == null ? 0 : listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ listeners.get(i).onAnimationEnd(this);
+ }
+ }
+
+ long getNativeAnimator() {
+ return mNativePtr.get();
}
// Called by native
@@ -181,7 +281,9 @@
long canvasProperty, float deltaValue);
private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
long canvasProperty, int paintField, float deltaValue);
- private static native void nSetDuration(long nativePtr, int duration);
- private static native int nGetDuration(long nativePtr);
+ private static native void nSetDuration(long nativePtr, long duration);
+ private static native long nGetDuration(long nativePtr);
+ private static native void nSetStartDelay(long nativePtr, long startDelay);
+ private static native long nGetStartDelay(long nativePtr);
private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 17035b1..74972c2 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -193,7 +193,7 @@
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
try {
- callbacks.onHardwarePostDraw(canvas);
+ callbacks.onHardwarePreDraw(canvas);
canvas.drawDisplayList(view.getDisplayList());
callbacks.onHardwarePostDraw(canvas);
} finally {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5141877..fb7d57d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4774,8 +4774,8 @@
mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);
}
- manageFocusHotspot(true, oldFocus);
onFocusChanged(true, direction, previouslyFocusedRect);
+ manageFocusHotspot(true, oldFocus);
refreshDrawableState();
}
}
@@ -6752,6 +6752,24 @@
}
/**
+ * Sets the pressed state for this view and provides a touch coordinate for
+ * animation hinting.
+ *
+ * @param pressed Pass true to set the View's internal state to "pressed",
+ * or false to reverts the View's internal state from a
+ * previously set "pressed" state.
+ * @param x The x coordinate of the touch that caused the press
+ * @param y The y coordinate of the touch that caused the press
+ */
+ private void setPressed(boolean pressed, float x, float y) {
+ if (pressed) {
+ setHotspot(R.attr.state_pressed, x, y);
+ }
+
+ setPressed(pressed);
+ }
+
+ /**
* Sets the pressed state for this view.
*
* @see #isClickable()
@@ -6769,6 +6787,10 @@
mPrivateFlags &= ~PFLAG_PRESSED;
}
+ if (!pressed) {
+ clearHotspot(R.attr.state_pressed);
+ }
+
if (needsRefresh) {
refreshDrawableState();
}
@@ -8993,7 +9015,6 @@
if ((viewFlags & ENABLED_MASK) == DISABLED) {
if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
- clearHotspot(R.attr.state_pressed);
setPressed(false);
}
// A disabled view that is clickable still consumes the touch
@@ -9026,8 +9047,7 @@
// showed it as pressed. Make it show the pressed
// state now (before scheduling the click) to ensure
// the user sees it.
- setHotspot(R.attr.state_pressed, x, y);
- setPressed(true);
+ setPressed(true, x, y);
}
if (!mHasPerformedLongPress) {
@@ -9061,8 +9081,6 @@
}
removeTapCallback();
- } else {
- clearHotspot(R.attr.state_pressed);
}
break;
@@ -9175,7 +9193,6 @@
*/
private void removeUnsetPressCallback() {
if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
- clearHotspot(R.attr.state_pressed);
setPressed(false);
removeCallbacks(mUnsetPressedState);
}
@@ -19234,8 +19251,7 @@
@Override
public void run() {
mPrivateFlags &= ~PFLAG_PREPRESSED;
- setHotspot(R.attr.state_pressed, x, y);
- setPressed(true);
+ setPressed(true, x, y);
checkForLongClick(ViewConfiguration.getTapTimeout());
}
}
@@ -19516,7 +19532,6 @@
private final class UnsetPressedState implements Runnable {
@Override
public void run() {
- clearHotspot(R.attr.state_pressed);
setPressed(false);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9b09d85..eed6412 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -111,6 +111,7 @@
private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
private static final boolean DEBUG_FPS = false;
+ private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
/**
* Set this system property to true to force the view hierarchy to render
@@ -668,6 +669,11 @@
public void detachFunctor(long functor) {
// TODO: Make the resize buffer some other way to not need this block
mBlockResizeBuffer = true;
+ if (mAttachInfo.mHardwareRenderer != null) {
+ // Fence so that any pending invokeFunctor() messages will be processed
+ // before we return from detachFunctor.
+ mAttachInfo.mHardwareRenderer.fence();
+ }
}
public boolean invokeFunctor(long functor, boolean waitForCompletion) {
@@ -3481,6 +3487,9 @@
* Called when an event is being delivered to the next stage.
*/
protected void onDeliverToNext(QueuedInputEvent q) {
+ if (DEBUG_INPUT_STAGES) {
+ Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
+ }
if (mNext != null) {
mNext.deliver(q);
} else {
@@ -5515,6 +5524,37 @@
return false;
}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
+ boolean hasPrevious = false;
+ hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
+ hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
+ hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
+ hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
+ hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
+ hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
+ if (!hasPrevious) {
+ sb.append("0");
+ }
+ sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
+ sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
+ sb.append(", mEvent=" + mEvent + "}");
+ return sb.toString();
+ }
+
+ private boolean flagToString(String name, int flag,
+ boolean hasPrevious, StringBuilder sb) {
+ if ((mFlags & flag) != 0) {
+ if (hasPrevious) {
+ sb.append("|");
+ }
+ sb.append(name);
+ return true;
+ }
+ return hasPrevious;
+ }
}
private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index ac12357..aaf0a75 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -30,6 +30,9 @@
private static final String CHROMIUM_WEBVIEW_FACTORY =
"com.android.webview.chromium.WebViewChromiumFactoryProvider";
+ private static final String NULL_WEBVIEW_FACTORY =
+ "com.android.webview.nullwebview.NullWebViewFactoryProvider";
+
private static final String LOGTAG = "WebViewFactory";
private static final boolean DEBUG = false;
@@ -88,6 +91,11 @@
}
private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
- return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+ try {
+ return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+ } catch (ClassNotFoundException e) {
+ Log.e(LOGTAG, "Chromium WebView does not exist");
+ return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
+ }
}
}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 438e164..74a3eec 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -666,6 +666,8 @@
case MotionEvent.ACTION_CANCEL: {
if (mTouchMode == TOUCH_MODE_DRAGGING) {
stopDrag(ev);
+ // Allow super class to handle pressed state, etc.
+ super.onTouchEvent(ev);
return true;
}
mTouchMode = TOUCH_MODE_IDLE;
@@ -801,7 +803,7 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ public void draw(Canvas c) {
final Rect tempRect = mTempRect;
final Drawable trackDrawable = mTrackDrawable;
final Drawable thumbDrawable = mThumbDrawable;
@@ -815,9 +817,6 @@
trackDrawable.getPadding(tempRect);
final int switchInnerLeft = switchLeft + tempRect.left;
- final int switchInnerTop = switchTop + tempRect.top;
- final int switchInnerRight = switchRight - tempRect.right;
- final int switchInnerBottom = switchBottom - tempRect.bottom;
// Relies on mTempRect, MUST be called first!
final int thumbPos = getThumbOffset();
@@ -833,8 +832,26 @@
background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
}
+ // Draw the background.
+ super.draw(c);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
+ final Rect tempRect = mTempRect;
+ final Drawable trackDrawable = mTrackDrawable;
+ final Drawable thumbDrawable = mThumbDrawable;
+ trackDrawable.getPadding(tempRect);
+
+ final int switchTop = mSwitchTop;
+ final int switchBottom = mSwitchBottom;
+ final int switchInnerLeft = mSwitchLeft + tempRect.left;
+ final int switchInnerTop = switchTop + tempRect.top;
+ final int switchInnerRight = mSwitchRight - tempRect.right;
+ final int switchInnerBottom = switchBottom - tempRect.bottom;
+
if (mSplitTrack) {
final Insets insets = thumbDrawable.getOpticalInsets();
thumbDrawable.copyBounds(tempRect);
@@ -861,7 +878,8 @@
}
mTextPaint.drawableState = drawableState;
- final int left = (thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2;
+ final Rect thumbBounds = thumbDrawable.getBounds();
+ final int left = (thumbBounds.left + thumbBounds.right) / 2 - switchText.getWidth() / 2;
final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
canvas.translate(left, top);
switchText.draw(canvas);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index cd75010..8e6fa58 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -17,6 +17,7 @@
package com.android.internal.app;
import android.app.AppOpsManager;
+import android.os.Bundle;
import com.android.internal.app.IAppOpsCallback;
interface IAppOpsService {
@@ -38,4 +39,10 @@
void resetAllModes();
int checkAudioOperation(int code, int stream, int uid, String packageName);
void setAudioRestriction(int code, int stream, int uid, int mode, in String[] exceptionPackages);
+
+ void setDeviceOwner(String packageName);
+ void setProfileOwner(String packageName, int userHandle);
+ void setUserRestrictions(in Bundle restrictions, int userHandle);
+ void removeUser(int userHandle);
+
}
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 79a8f44..a238ae3 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -183,7 +183,7 @@
private void init(View decor) {
mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
- com.android.internal.R.id.action_bar_overlay_layout);
+ com.android.internal.R.id.decor_content_parent);
if (mOverlayLayout != null) {
mOverlayLayout.setActionBarVisibilityCallback(this);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 956c86d..8428f66 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -235,7 +235,8 @@
int mWakeLockNesting;
boolean mWakeLockImportant;
- public boolean mRecordAllWakeLocks;
+ boolean mRecordAllWakeLocks;
+ boolean mNoAutoReset;
int mScreenState = Display.STATE_UNKNOWN;
StopwatchTimer mScreenOnTimer;
@@ -2314,9 +2315,6 @@
}
}
- private String mInitialAcquireWakeName;
- private int mInitialAcquireWakeUid = -1;
-
public void setRecordAllWakeLocksLocked(boolean enabled) {
mRecordAllWakeLocks = enabled;
if (!enabled) {
@@ -2325,6 +2323,13 @@
}
}
+ public void setNoAutoReset(boolean enabled) {
+ mNoAutoReset = enabled;
+ }
+
+ private String mInitialAcquireWakeName;
+ private int mInitialAcquireWakeUid = -1;
+
public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
boolean unimportantForLogging, long elapsedRealtime, long uptime) {
uid = mapUid(uid);
@@ -2355,6 +2360,7 @@
} else if (mRecordAllWakeLocks) {
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
uid, 0)) {
+ mWakeLockNesting++;
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_START,
@@ -5942,9 +5948,9 @@
// we have gone through a significant charge (from a very low
// level to a now very high level).
boolean reset = false;
- if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+ if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
|| level >= 90
- || (mDischargeCurrentLevel < 20 && level >= 80)) {
+ || (mDischargeCurrentLevel < 20 && level >= 80))) {
doWrite = true;
resetAllStatsLocked();
mDischargeStartLevel = level;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 75feb5d..8fa662d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -36,9 +36,12 @@
void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
void setHardKeyboardStatus(boolean available, boolean enabled);
+ void setWindowState(int window, int state);
+
+ void showRecentApps(boolean triggeredFromAltTab);
+ void hideRecentApps();
void toggleRecentApps();
void preloadRecentApps();
void cancelPreloadRecentApps();
- void setWindowState(int window, int state);
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index cf334c3..9ebfd78 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -52,8 +52,11 @@
in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys);
void setSystemUiVisibility(int vis, int mask);
void setHardKeyboardEnabled(boolean enabled);
+ void setWindowState(int window, int state);
+
+ void showRecentApps(boolean triggeredFromAltTab);
+ void hideRecentApps();
void toggleRecentApps();
void preloadRecentApps();
void cancelPreloadRecentApps();
- void setWindowState(int window, int state);
}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 4b84941..81e67d8 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -48,6 +48,8 @@
public static final int BASE_WIFI_CONTROLLER = 0x00026000;
public static final int BASE_WIFI_SCANNER = 0x00027000;
public static final int BASE_WIFI_SCANNER_SERVICE = 0x00027100;
+ public static final int BASE_WIFI_PASSPOINT_MANAGER = 0x00028000;
+ public static final int BASE_WIFI_PASSPOINT_SERVICE = 0x00028100;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index aec2b7e..1feb943 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -34,11 +34,11 @@
* Used to cache the float[] LUT for use across multiple native
* interpolator creation
*/
- public FallbackLUTInterpolator(TimeInterpolator interpolator, int duration) {
+ public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) {
mLut = createLUT(interpolator, duration);
}
- private static float[] createLUT(TimeInterpolator interpolator, int duration) {
+ private static float[] createLUT(TimeInterpolator interpolator, long duration) {
long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
int numAnimFrames = (int) Math.ceil(duration / animIntervalMs);
@@ -59,7 +59,7 @@
/**
* Used to create a one-shot float[] LUT & native interpolator
*/
- public static long createNativeInterpolator(TimeInterpolator interpolator, int duration) {
+ public static long createNativeInterpolator(TimeInterpolator interpolator, long duration) {
float[] lut = createLUT(interpolator, duration);
return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
}
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 19d58bf..7ab4bed 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -19,26 +19,34 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.IntProperty;
+import android.util.Log;
import android.util.Property;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
+import android.view.Window;
import android.view.WindowInsets;
import android.widget.OverScroller;
+import com.android.internal.view.menu.MenuPresenter;
/**
* Special layout for the containing of an overlay action bar (and its
* content) to correctly handle fitting system windows when the content
* has request that its layout ignore them.
*/
-public class ActionBarOverlayLayout extends ViewGroup {
+public class ActionBarOverlayLayout extends ViewGroup implements DecorContentParent {
private static final String TAG = "ActionBarOverlayLayout";
private int mActionBarHeight;
@@ -47,7 +55,7 @@
// The main UI elements that we handle the layout of.
private View mContent;
- private View mActionBarBottom;
+ private ActionBarContainer mActionBarBottom;
private ActionBarContainer mActionBarTop;
// Some interior UI elements.
@@ -556,7 +564,8 @@
mActionBarTop = (ActionBarContainer) findViewById(
com.android.internal.R.id.action_bar_container);
mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
- mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
+ mActionBarBottom = (ActionBarContainer) findViewById(
+ com.android.internal.R.id.split_action_bar);
}
}
@@ -629,6 +638,179 @@
return finalY > mActionBarTop.getHeight();
}
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (super.dispatchKeyEvent(event)) {
+ return true;
+ }
+
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ final int action = event.getAction();
+
+ // Collapse any expanded action views.
+ if (mActionBarView != null && mActionBarView.hasExpandedActionView()) {
+ if (action == KeyEvent.ACTION_UP) {
+ mActionBarView.collapseActionView();
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void setWindowCallback(Window.Callback cb) {
+ pullChildren();
+ mActionBarView.setWindowCallback(cb);
+ }
+
+ @Override
+ public void setWindowTitle(CharSequence title) {
+ pullChildren();
+ mActionBarView.setWindowTitle(title);
+ }
+
+ @Override
+ public CharSequence getTitle() {
+ pullChildren();
+ return mActionBarView.getTitle();
+ }
+
+ @Override
+ public void initFeature(int windowFeature) {
+ pullChildren();
+ switch (windowFeature) {
+ case Window.FEATURE_PROGRESS:
+ mActionBarView.initProgress();
+ break;
+ case Window.FEATURE_INDETERMINATE_PROGRESS:
+ mActionBarView.initIndeterminateProgress();
+ break;
+ case Window.FEATURE_ACTION_BAR_OVERLAY:
+ setOverlayMode(true);
+ break;
+ }
+ }
+
+ @Override
+ public void setUiOptions(int uiOptions) {
+ boolean splitActionBar = false;
+ final boolean splitWhenNarrow =
+ (uiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
+ if (splitWhenNarrow) {
+ splitActionBar = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.split_action_bar_is_narrow);
+ }
+ if (splitActionBar) {
+ pullChildren();
+ if (mActionBarBottom != null) {
+ mActionBarView.setSplitView(mActionBarBottom);
+ mActionBarView.setSplitActionBar(splitActionBar);
+ mActionBarView.setSplitWhenNarrow(splitWhenNarrow);
+
+ final ActionBarContextView cab = (ActionBarContextView) findViewById(
+ com.android.internal.R.id.action_context_bar);
+ cab.setSplitView(mActionBarBottom);
+ cab.setSplitActionBar(splitActionBar);
+ cab.setSplitWhenNarrow(splitWhenNarrow);
+ } else if (splitActionBar) {
+ Log.e(TAG, "Requested split action bar with " +
+ "incompatible window decor! Ignoring request.");
+ }
+ }
+ }
+
+ @Override
+ public boolean hasIcon() {
+ pullChildren();
+ return mActionBarView.hasIcon();
+ }
+
+ @Override
+ public boolean hasLogo() {
+ pullChildren();
+ return mActionBarView.hasLogo();
+ }
+
+ @Override
+ public void setIcon(int resId) {
+ pullChildren();
+ mActionBarView.setIcon(resId);
+ }
+
+ @Override
+ public void setIcon(Drawable d) {
+ pullChildren();
+ mActionBarView.setIcon(d);
+ }
+
+ @Override
+ public void setLogo(int resId) {
+ pullChildren();
+ mActionBarView.setLogo(resId);
+ }
+
+ @Override
+ public boolean canShowOverflowMenu() {
+ pullChildren();
+ return mActionBarView.isOverflowReserved() && mActionBarView.getVisibility() == VISIBLE;
+ }
+
+ @Override
+ public boolean isOverflowMenuShowing() {
+ pullChildren();
+ return mActionBarView.isOverflowMenuShowing();
+ }
+
+ @Override
+ public boolean isOverflowMenuShowPending() {
+ pullChildren();
+ return mActionBarView.isOverflowMenuShowPending();
+ }
+
+ @Override
+ public boolean showOverflowMenu() {
+ pullChildren();
+ return mActionBarView.showOverflowMenu();
+ }
+
+ @Override
+ public boolean hideOverflowMenu() {
+ pullChildren();
+ return mActionBarView.hideOverflowMenu();
+ }
+
+ @Override
+ public void setMenuPrepared() {
+ pullChildren();
+ mActionBarView.setMenuPrepared();
+ }
+
+ @Override
+ public void setMenu(Menu menu, MenuPresenter.Callback cb) {
+ pullChildren();
+ mActionBarView.setMenu(menu, cb);
+ }
+
+ @Override
+ public void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
+ pullChildren();
+ mActionBarView.saveHierarchyState(toolbarStates);
+ }
+
+ @Override
+ public void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
+ pullChildren();
+ mActionBarView.restoreHierarchyState(toolbarStates);
+ }
+
+ @Override
+ public void dismissPopups() {
+ pullChildren();
+ mActionBarView.dismissPopupMenus();
+ }
+
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/core/java/com/android/internal/widget/DecorContentParent.java b/core/java/com/android/internal/widget/DecorContentParent.java
new file mode 100644
index 0000000..4fa370a
--- /dev/null
+++ b/core/java/com/android/internal/widget/DecorContentParent.java
@@ -0,0 +1,53 @@
+/*
+ * 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.widget;
+
+import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
+import android.util.SparseArray;
+import android.view.Menu;
+import android.view.Window;
+import com.android.internal.view.menu.MenuPresenter;
+
+/**
+ * Implemented by the top-level decor layout for a window. DecorContentParent offers
+ * entry points for a number of title/window decor features.
+ */
+public interface DecorContentParent {
+ void setWindowCallback(Window.Callback cb);
+ void setWindowTitle(CharSequence title);
+ CharSequence getTitle();
+ void initFeature(int windowFeature);
+ void setUiOptions(int uiOptions);
+ boolean hasIcon();
+ boolean hasLogo();
+ void setIcon(int resId);
+ void setIcon(Drawable d);
+ void setLogo(int resId);
+ boolean canShowOverflowMenu();
+ boolean isOverflowMenuShowing();
+ boolean isOverflowMenuShowPending();
+ boolean showOverflowMenu();
+ boolean hideOverflowMenu();
+ void setMenuPrepared();
+ void setMenu(Menu menu, MenuPresenter.Callback cb);
+ void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
+ void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
+ void dismissPopups();
+
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 0ad2ab2..99bbe39 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -228,6 +228,7 @@
libz \
libaudioutils \
libpdfrenderer \
+ libimg_utils \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index bf58918..9279758 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -367,7 +367,6 @@
bool forceLTR = false;
bool forceRTL = false;
- ALOGD("computeValues dirFlags=%d", dirFlags);
switch (dirFlags & kBidi_Mask) {
case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index fa2cfe3..3312109 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -30,6 +30,7 @@
#include "JNIHelp.h"
#include "android_os_Parcel.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
#include <binder/IServiceManager.h>
#include <camera/CameraMetadata.h>
@@ -57,6 +58,31 @@
static fields_t fields;
+namespace android {
+
+status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
+ /*out*/CameraMetadata* metadata) {
+ if (!thiz) {
+ ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (!metadata) {
+ ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
+ fields.metadata_ptr));
+ if (nativePtr == NULL) {
+ ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ *metadata = *nativePtr;
+ return OK;
+}
+
+} /*namespace android*/
+
namespace {
struct Helpers {
static size_t getTypeSize(uint8_t type) {
diff --git a/core/jni/android_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
new file mode 100644
index 0000000..4907830
--- /dev/null
+++ b/core/jni/android_media_AudioErrors.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIOERRORS_H
+#define ANDROID_MEDIA_AUDIOERRORS_H
+
+#include <utils/Errors.h>
+
+namespace android {
+// status codes used by JAVA APIs. Translation from native error codes is done by
+// nativeToJavaStatus()
+// must be kept in sync with values in
+// frameworks/base/media/java/android/media/AudioSystem.java.
+enum {
+ AUDIO_JAVA_SUCCESS = 0,
+ AUDIO_JAVA_ERROR = -1,
+ AUDIO_JAVA_BAD_VALUE = -2,
+ AUDIO_JAVA_INVALID_OPERATION = -3,
+ AUDIO_JAVA_PERMISSION_DENIED = -4,
+ AUDIO_JAVA_NO_INIT = -5,
+ AUDIO_JAVA_DEAD_OBJECT = -6,
+};
+
+static inline jint nativeToJavaStatus(status_t status) {
+ switch (status) {
+ case NO_ERROR:
+ return AUDIO_JAVA_SUCCESS;
+ case BAD_VALUE:
+ return AUDIO_JAVA_BAD_VALUE;
+ case INVALID_OPERATION:
+ return AUDIO_JAVA_INVALID_OPERATION;
+ case PERMISSION_DENIED:
+ return AUDIO_JAVA_PERMISSION_DENIED;
+ case NO_INIT:
+ return AUDIO_JAVA_NO_INIT;
+ case DEAD_OBJECT:
+ return AUDIO_JAVA_DEAD_OBJECT;
+ default:
+ return AUDIO_JAVA_ERROR;
+ }
+}
+}; // namespace android
+#endif // ANDROID_MEDIA_AUDIOERRORS_H
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 09bdc61..a54eba1 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -27,6 +27,7 @@
#include <media/AudioRecord.h>
#include "android_media_AudioFormat.h"
+#include "android_media_AudioErrors.h"
// ----------------------------------------------------------------------------
@@ -55,29 +56,12 @@
// ----------------------------------------------------------------------------
-#define AUDIORECORD_SUCCESS 0
-#define AUDIORECORD_ERROR -1
-#define AUDIORECORD_ERROR_BAD_VALUE -2
-#define AUDIORECORD_ERROR_INVALID_OPERATION -3
#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
-jint android_media_translateRecorderErrorCode(int code) {
- switch (code) {
- case NO_ERROR:
- return AUDIORECORD_SUCCESS;
- case BAD_VALUE:
- return AUDIORECORD_ERROR_BAD_VALUE;
- case INVALID_OPERATION:
- return AUDIORECORD_ERROR_INVALID_OPERATION;
- default:
- return AUDIORECORD_ERROR;
- }
-}
-
// ----------------------------------------------------------------------------
static void recorderCallback(int event, void* user, void *info) {
@@ -197,13 +181,13 @@
if (jSession == NULL) {
ALOGE("Error creating AudioRecord: invalid session ID pointer");
- return (jint) AUDIORECORD_ERROR;
+ return (jint) AUDIO_JAVA_ERROR;
}
jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
- return (jint) AUDIORECORD_ERROR;
+ return (jint) AUDIO_JAVA_ERROR;
}
int sessionId = nSession[0];
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
@@ -259,7 +243,7 @@
// of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
- return (jint) AUDIORECORD_SUCCESS;
+ return (jint) AUDIO_JAVA_SUCCESS;
// failure:
native_init_failure:
@@ -280,10 +264,10 @@
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return (jint) AUDIORECORD_ERROR;
+ return (jint) AUDIO_JAVA_ERROR;
}
- return (jint) android_media_translateRecorderErrorCode(
+ return nativeToJavaStatus(
lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession));
}
@@ -383,7 +367,7 @@
env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
if (readSize < 0) {
- readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
}
return (jint) readSize;
}
@@ -428,7 +412,7 @@
env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
if (readSize < 0) {
- readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
} else {
readSize /= sizeof(short);
}
@@ -461,7 +445,7 @@
ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
capacity < sizeInBytes ? capacity : sizeInBytes);
if (readSize < 0) {
- readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
}
return (jint)readSize;
}
@@ -475,9 +459,9 @@
if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for setMarkerPosition()");
- return AUDIORECORD_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );
+ return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
}
@@ -490,7 +474,7 @@
if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for getMarkerPosition()");
- return AUDIORECORD_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
lpRecorder->getMarkerPosition(&markerPos);
return (jint)markerPos;
@@ -506,9 +490,9 @@
if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
- return AUDIORECORD_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );
+ return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
}
@@ -521,7 +505,7 @@
if (lpRecorder == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
- return AUDIORECORD_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
lpRecorder->getPositionUpdatePeriod(&period);
return (jint)period;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 463a0a8..e548e91 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -32,6 +32,7 @@
#include <binder/MemoryBase.h>
#include "android_media_AudioFormat.h"
+#include "android_media_AudioErrors.h"
// ----------------------------------------------------------------------------
@@ -94,31 +95,12 @@
// ----------------------------------------------------------------------------
#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
-#define AUDIOTRACK_SUCCESS 0
-#define AUDIOTRACK_ERROR -1
-#define AUDIOTRACK_ERROR_BAD_VALUE -2
-#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
-
-jint android_media_translateErrorCode(int code) {
- switch (code) {
- case NO_ERROR:
- return AUDIOTRACK_SUCCESS;
- case BAD_VALUE:
- return AUDIOTRACK_ERROR_BAD_VALUE;
- case INVALID_OPERATION:
- return AUDIOTRACK_ERROR_INVALID_OPERATION;
- default:
- return AUDIOTRACK_ERROR;
- }
-}
-
-
// ----------------------------------------------------------------------------
static void audioCallback(int event, void* user, void *info) {
@@ -201,22 +183,6 @@
{
ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
- uint32_t afSampleRate;
- size_t afFrameCount;
-
- status_t status = AudioSystem::getOutputFrameCount(&afFrameCount,
- (audio_stream_type_t) streamType);
- if (status != NO_ERROR) {
- ALOGE("Error %d creating AudioTrack: Could not get AudioSystem frame count "
- "for stream type %d.", status, streamType);
- return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
- }
- status = AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType);
- if (status != NO_ERROR) {
- ALOGE("Error %d creating AudioTrack: Could not get AudioSystem sampling rate "
- "for stream type %d.", status, streamType);
- return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
- }
// Java channel masks don't map directly to the native definition, but it's a simple shift
// to skip the two deprecated channel configurations "default" and "mono".
@@ -229,23 +195,8 @@
uint32_t channelCount = popcount(nativeChannelMask);
- // check the stream type
- audio_stream_type_t atStreamType;
- switch (streamType) {
- case AUDIO_STREAM_VOICE_CALL:
- case AUDIO_STREAM_SYSTEM:
- case AUDIO_STREAM_RING:
- case AUDIO_STREAM_MUSIC:
- case AUDIO_STREAM_ALARM:
- case AUDIO_STREAM_NOTIFICATION:
- case AUDIO_STREAM_BLUETOOTH_SCO:
- case AUDIO_STREAM_DTMF:
- atStreamType = (audio_stream_type_t) streamType;
- break;
- default:
- ALOGE("Error creating AudioTrack: unknown stream type %d.", streamType);
- return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
- }
+ // stream type already checked in Java
+ audio_stream_type_t atStreamType = (audio_stream_type_t) streamType;
// check the format.
// This function was called from Java, so we compare the format against the Java constants
@@ -280,13 +231,13 @@
if (jSession == NULL) {
ALOGE("Error creating AudioTrack: invalid session ID pointer");
- return (jint) AUDIOTRACK_ERROR;
+ return (jint) AUDIO_JAVA_ERROR;
}
jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
if (nSession == NULL) {
ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
- return (jint) AUDIOTRACK_ERROR;
+ return (jint) AUDIO_JAVA_ERROR;
}
int sessionId = nSession[0];
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
@@ -305,6 +256,7 @@
lpJniStorage->mCallbackData.busy = false;
// initialize the native AudioTrack object
+ status_t status = NO_ERROR;
switch (memoryMode) {
case MODE_STREAM:
@@ -376,7 +328,7 @@
//ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
- return (jint) AUDIOTRACK_SUCCESS;
+ return (jint) AUDIO_JAVA_SUCCESS;
// failures:
native_init_failure:
@@ -626,7 +578,7 @@
ScopedBytesRO bytes(env, javaBytes);
if (bytes.get() == NULL) {
ALOGE("Error retrieving source of audio data to play, can't play");
- return AUDIOTRACK_ERROR_BAD_VALUE;
+ return (jint)AUDIO_JAVA_BAD_VALUE;
}
jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
@@ -725,7 +677,7 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for frameCount()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
return lpTrack->frameCount();
@@ -739,9 +691,9 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setSampleRate()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
+ return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
}
@@ -751,7 +703,7 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getSampleRate()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
return (jint) lpTrack->getSampleRate();
}
@@ -764,9 +716,9 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setMarkerPosition()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
+ return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
}
@@ -778,7 +730,7 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getMarkerPosition()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
lpTrack->getMarkerPosition(&markerPos);
return (jint)markerPos;
@@ -792,9 +744,9 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
+ return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
}
@@ -806,7 +758,7 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
lpTrack->getPositionUpdatePeriod(&period);
return (jint)period;
@@ -820,9 +772,9 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setPosition()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateErrorCode( lpTrack->setPosition(position) );
+ return nativeToJavaStatus( lpTrack->setPosition(position) );
}
@@ -834,7 +786,7 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for getPosition()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
lpTrack->getPosition(&position);
return (jint)position;
@@ -848,7 +800,7 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for latency()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
return (jint)lpTrack->latency();
}
@@ -860,7 +812,7 @@
if (lpTrack == NULL) {
ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
AudioTimestamp timestamp;
status_t status = lpTrack->getTimestamp(timestamp);
@@ -868,13 +820,13 @@
jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
if (nTimestamp == NULL) {
ALOGE("Unable to get array for getTimestamp()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
nTimestamp[0] = (jlong) timestamp.mPosition;
nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
}
- return (jint) android_media_translateErrorCode(status);
+ return (jint) nativeToJavaStatus(status);
}
@@ -885,9 +837,9 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for setLoop()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
+ return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
}
@@ -897,9 +849,9 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for reload()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateErrorCode( lpTrack->reload() );
+ return nativeToJavaStatus( lpTrack->reload() );
}
@@ -982,9 +934,9 @@
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for attachAuxEffect()");
- return AUDIOTRACK_ERROR;
+ return (jint)AUDIO_JAVA_ERROR;
}
- return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
+ return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
}
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index ea2f96e..e19ce36 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -116,15 +116,26 @@
return reinterpret_cast<jlong>( animator );
}
-static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
+static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong duration) {
LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
animator->setDuration(duration);
}
-static jint getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+static jlong getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
- return static_cast<jint>(animator->duration());
+ return static_cast<jlong>(animator->duration());
+}
+
+static void setStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong startDelay) {
+ LOG_ALWAYS_FATAL_IF(startDelay < 0, "Start delay cannot be negative");
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+ animator->setStartDelay(startDelay);
+}
+
+static jlong getStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+ return static_cast<jlong>(animator->startDelay());
}
static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
@@ -146,8 +157,10 @@
{ "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IF)J", (void*) createAnimator },
{ "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JF)J", (void*) createCanvasPropertyFloatAnimator },
{ "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyPaintAnimator },
- { "nSetDuration", "(JI)V", (void*) setDuration },
- { "nGetDuration", "(J)I", (void*) getDuration },
+ { "nSetDuration", "(JJ)V", (void*) setDuration },
+ { "nGetDuration", "(J)J", (void*) getDuration },
+ { "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
+ { "nGetStartDelay", "(J)J", (void*) getStartDelay },
{ "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
#endif
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4eac802..a97d5fc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2056,7 +2056,7 @@
android:protectionLevel="signature|system" />
<!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
- to ensure that only the system can bind to it. -->
+ to ensure that only the system can bind to it. @hide -->
<permission android:name="android.permission.BIND_VOICE_INTERACTION"
android:label="@string/permlab_bindVoiceInteraction"
android:description="@string/permdesc_bindVoiceInteraction"
@@ -2079,7 +2079,7 @@
<!-- Must be required by a {@link android.media.routeprovider.RouteProviderService}
to ensure that only the system can interact with it.
- -->
+ @hide -->
<permission android:name="android.permission.BIND_ROUTE_PROVIDER"
android:label="@string/permlab_bindRouteProvider"
android:description="@string/permdesc_bindRouteProvider"
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
deleted file mode 100644
index 02c99fe..0000000
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?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.
--->
-
-<!--
-This is an optimized layout for a screen with
-the Action Bar enabled overlaying application content.
--->
-
-<com.android.internal.widget.ActionBarOverlayLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/action_bar_overlay_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:splitMotionEvents="false">
- <FrameLayout android:id="@android:id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <com.android.internal.widget.ActionBarContainer
- android:id="@+id/action_bar_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- style="?android:attr/actionBarStyle"
- android:viewName="android:action_bar"
- android:gravity="top">
- <com.android.internal.widget.ActionBarView
- android:id="@+id/action_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="?android:attr/actionBarStyle" />
- <com.android.internal.widget.ActionBarContextView
- android:id="@+id/action_context_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"
- style="?android:attr/actionModeStyle" />
- </com.android.internal.widget.ActionBarContainer>
-</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/layout/notification_action.xml b/core/res/res/layout/notification_action.xml
deleted file mode 100644
index 4e7c74c..0000000
--- a/core/res/res/layout/notification_action.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="?android:attr/borderlessButtonStyle"
- android:id="@+id/action0"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:gravity="start|center_vertical"
- android:drawablePadding="8dp"
- android:paddingStart="8dp"
- android:textColor="#ccc"
- android:textSize="14dp"
- android:singleLine="true"
- android:ellipsize="end"
- />
diff --git a/core/res/res/layout/notification_action_tombstone.xml b/core/res/res/layout/notification_action_tombstone.xml
deleted file mode 100644
index 9977cfe..0000000
--- a/core/res/res/layout/notification_action_tombstone.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="?android:attr/borderlessButtonStyle"
- android:id="@+id/action0"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:gravity="start|center_vertical"
- android:drawablePadding="8dp"
- android:paddingStart="8dp"
- android:textColor="#ccc"
- android:textSize="14dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:alpha="0.5"
- android:enabled="false"
- />
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
deleted file mode 100644
index d2e25c1..0000000
--- a/core/res/res/layout/notification_template_base.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:internal="http://schemas.android.com/apk/prv/res/android"
- android:background="@android:drawable/notification_bg"
- android:id="@+id/status_bar_latest_event_content"
- android:layout_width="match_parent"
- android:layout_height="64dp"
- internal:layout_minHeight="64dp"
- internal:layout_maxHeight="64dp"
- >
- <ImageView android:id="@+id/icon"
- android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_height"
- android:background="@android:drawable/notification_template_icon_bg"
- android:scaleType="center"
- />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_vertical"
- android:layout_marginStart="@dimen/notification_large_icon_width"
- android:minHeight="@dimen/notification_large_icon_height"
- android:orientation="vertical"
- android:paddingEnd="8dp"
- android:paddingTop="2dp"
- android:paddingBottom="2dp"
- android:gravity="top"
- >
- <LinearLayout
- android:id="@+id/line1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="6dp"
- android:layout_marginStart="8dp"
- android:orientation="horizontal"
- >
- <TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:layout_weight="1"
- />
- <ViewStub android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_time"
- />
- <ViewStub android:id="@+id/chronometer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_chronometer"
- />
- </LinearLayout>
- <TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="-2dp"
- android:layout_marginBottom="-2dp"
- android:layout_marginStart="8dp"
- android:singleLine="true"
- android:fadingEdge="horizontal"
- android:ellipsize="marquee"
- android:visibility="gone"
- />
- <ProgressBar
- android:id="@android:id/progress"
- android:layout_width="match_parent"
- android:layout_height="12dp"
- android:layout_marginStart="8dp"
- android:visibility="gone"
- style="?android:attr/progressBarStyleHorizontal"
- />
- <LinearLayout
- android:id="@+id/line3"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:layout_marginStart="8dp"
- >
- <TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- />
- <TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:singleLine="true"
- android:gravity="center"
- android:paddingStart="8dp"
- />
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
- </LinearLayout>
- </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
deleted file mode 100644
index 7cc6650..0000000
--- a/core/res/res/layout/notification_template_big_base.xml
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:internal="http://schemas.android.com/apk/prv/res/android"
- android:background="@android:drawable/notification_bg"
- android:id="@+id/status_bar_latest_event_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- internal:layout_minHeight="65dp"
- internal:layout_maxHeight="unbounded"
- >
- <ImageView android:id="@+id/icon"
- android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_height"
- android:background="@android:drawable/notification_template_icon_bg"
- android:scaleType="center"
- />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_vertical"
- android:minHeight="@dimen/notification_large_icon_height"
- android:orientation="vertical"
- android:gravity="top"
- >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/notification_large_icon_width"
- android:minHeight="@dimen/notification_large_icon_height"
- android:paddingTop="2dp"
- android:orientation="vertical"
- >
- <LinearLayout
- android:id="@+id/line1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="6dp"
- android:layout_marginEnd="8dp"
- android:layout_marginStart="8dp"
- android:orientation="horizontal"
- >
- <TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:layout_weight="1"
- />
- <ViewStub android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_time"
- />
- <ViewStub android:id="@+id/chronometer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_chronometer"
- />
- </LinearLayout>
- <TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="-2dp"
- android:layout_marginBottom="-2dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:fadingEdge="horizontal"
- android:ellipsize="marquee"
- android:visibility="gone"
- />
- <TextView android:id="@+id/big_text"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="false"
- android:visibility="gone"
- />
- <LinearLayout
- android:id="@+id/line3"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- >
- <TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- />
- <TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:singleLine="true"
- android:gravity="center"
- android:paddingStart="8dp"
- />
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
- </LinearLayout>
- <ProgressBar
- android:id="@android:id/progress"
- android:layout_width="match_parent"
- android:layout_height="12dp"
- android:layout_marginBottom="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:visibility="gone"
- style="?android:attr/progressBarStyleHorizontal"
- />
- </LinearLayout>
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:id="@+id/action_divider"
- android:visibility="gone"
- android:background="?android:attr/dividerHorizontal" />
- <include
- layout="@layout/notification_action_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/notification_large_icon_width"
- />
- </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
deleted file mode 100644
index f3f3951..0000000
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:internal="http://schemas.android.com/apk/prv/res/android"
- android:background="@android:drawable/notification_bg"
- android:id="@+id/status_bar_latest_event_content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- internal:layout_minHeight="65dp"
- internal:layout_maxHeight="unbounded"
- >
- <ImageView
- android:id="@+id/big_picture"
- android:layout_width="match_parent"
- android:layout_height="192dp"
- android:layout_marginTop="64dp"
- android:layout_gravity="bottom"
- android:scaleType="centerCrop"
- />
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="6dp"
- android:layout_marginTop="64dp"
- android:scaleType="fitXY"
- android:src="@drawable/title_bar_shadow"
- />
- <include layout="@layout/notification_template_base"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="208dp"
- android:paddingStart="64dp"
- android:layout_gravity="bottom"
- android:background="#CC111111"
- >
- <include
- layout="@layout/notification_action_list"
- android:id="@+id/actions"
- android:layout_gravity="bottom"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
- </FrameLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
deleted file mode 100644
index 7e6da22..0000000
--- a/core/res/res/layout/notification_template_big_text.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:internal="http://schemas.android.com/apk/prv/res/android"
- android:background="@android:drawable/notification_bg"
- android:id="@+id/status_bar_latest_event_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- internal:layout_minHeight="65dp"
- internal:layout_maxHeight="unbounded"
- >
- <ImageView android:id="@+id/icon"
- android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_height"
- android:background="@android:drawable/notification_template_icon_bg"
- android:scaleType="center"
- />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_vertical"
- android:layout_marginStart="@dimen/notification_large_icon_width"
- android:orientation="vertical"
- android:paddingTop="0dp"
- android:paddingBottom="2dp"
- android:gravity="top"
- >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/notification_large_icon_height"
- android:orientation="vertical"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:layout_weight="1"
- >
- <LinearLayout
- android:id="@+id/line1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:orientation="horizontal"
- android:layout_gravity="top"
- android:layout_weight="0"
- >
- <TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:layout_weight="1"
- />
- <ViewStub android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_time"
- />
- <ViewStub android:id="@+id/chronometer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_chronometer"
- />
- </LinearLayout>
- <TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="-2dp"
- android:layout_marginBottom="-2dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:fadingEdge="horizontal"
- android:ellipsize="marquee"
- android:layout_weight="0"
- android:visibility="gone"
- />
- <ProgressBar
- android:id="@android:id/progress"
- android:layout_width="match_parent"
- android:layout_height="12dp"
- android:layout_marginBottom="8dp"
- android:layout_marginEnd="8dp"
- android:visibility="gone"
- android:layout_weight="0"
- style="?android:attr/progressBarStyleHorizontal"
- />
- <TextView android:id="@+id/big_text"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginBottom="10dp"
- android:layout_marginEnd="8dp"
- android:singleLine="false"
- android:visibility="gone"
- android:maxLines="8"
- android:ellipsize="end"
- android:layout_weight="1"
- />
- </LinearLayout>
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:layout_marginTop="-1px"
- android:id="@+id/action_divider"
- android:visibility="gone"
- android:background="?android:attr/dividerHorizontal" />
- <include
- layout="@layout/notification_action_list"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:id="@+id/overflow_divider"
- android:layout_marginBottom="8dp"
- android:visibility="visible"
- android:background="?android:attr/dividerHorizontal" />
- <LinearLayout
- android:id="@+id/line3"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginBottom="8dp"
- android:layout_marginEnd="8dp"
- android:orientation="horizontal"
- android:layout_weight="0"
- android:gravity="center_vertical"
- >
- <TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- />
- <TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:singleLine="true"
- android:gravity="center"
- android:paddingStart="8dp"
- />
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
- </LinearLayout>
- </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_icon_group.xml b/core/res/res/layout/notification_template_icon_group.xml
new file mode 100644
index 0000000..2ad6f9e
--- /dev/null
+++ b/core/res/res/layout/notification_template_icon_group.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:id="@+id/icon_group"
+ >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:padding="8dp"
+ android:scaleType="centerInside"
+ />
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:padding="4dp"
+ android:layout_gravity="end|bottom"
+ android:scaleType="centerInside"
+ android:visibility="gone"
+ android:layout_marginEnd="3dp"
+ android:layout_marginBottom="3dp"
+ />
+</FrameLayout>
+
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
deleted file mode 100644
index 1eec871..0000000
--- a/core/res/res/layout/notification_template_inbox.xml
+++ /dev/null
@@ -1,267 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:internal="http://schemas.android.com/apk/prv/res/android"
- android:id="@+id/status_bar_latest_event_content"
- android:background="@android:drawable/notification_bg"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- internal:layout_minHeight="65dp"
- internal:layout_maxHeight="unbounded"
- >
- <ImageView android:id="@+id/icon"
- android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_height"
- android:background="@android:drawable/notification_template_icon_bg"
- android:scaleType="center"
- />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_vertical"
- android:layout_marginStart="@dimen/notification_large_icon_width"
- android:minHeight="@dimen/notification_large_icon_height"
- android:orientation="vertical"
- android:paddingTop="0dp"
- android:paddingBottom="2dp"
- android:gravity="top"
- >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/notification_large_icon_height"
- android:paddingTop="2dp"
- android:orientation="vertical"
- >
- <LinearLayout
- android:id="@+id/line1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:paddingTop="6dp"
- android:orientation="horizontal"
- android:layout_weight="0"
- >
- <TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:layout_weight="1"
- />
- <ViewStub android:id="@+id/time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_time"
- />
- <ViewStub android:id="@+id/chronometer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:visibility="gone"
- android:layout="@layout/notification_template_part_chronometer"
- />
- </LinearLayout>
- <TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="-2dp"
- android:layout_marginBottom="-2dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:fadingEdge="horizontal"
- android:ellipsize="marquee"
- android:visibility="gone"
- android:layout_weight="0"
- />
- <ProgressBar
- android:id="@android:id/progress"
- android:layout_width="match_parent"
- android:layout_height="12dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:visibility="gone"
- android:layout_weight="0"
- style="?android:attr/progressBarStyleHorizontal"
- />
- <TextView android:id="@+id/inbox_text0"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text1"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text2"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text3"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text4"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text5"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_text6"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- />
- <TextView android:id="@+id/inbox_more"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="end"
- android:visibility="gone"
- android:layout_weight="1"
- android:text="@android:string/ellipsis"
- />
- <FrameLayout
- android:id="@+id/inbox_end_pad"
- android:layout_width="match_parent"
- android:layout_height="8dip"
- android:visibility="gone"
- android:layout_weight="0"
- />
- </LinearLayout>
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:layout_marginTop="-1px"
- android:id="@+id/action_divider"
- android:background="?android:attr/dividerHorizontal" />
- <include
- layout="@layout/notification_action_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- />
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:layout_marginTop="-1px"
- android:id="@+id/overflow_divider"
- android:visibility="visible"
- android:background="?android:attr/dividerHorizontal" />
- <LinearLayout
- android:id="@+id/line3"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginBottom="8dp"
- android:layout_marginEnd="8dp"
- android:orientation="horizontal"
- android:layout_weight="0"
- android:gravity="center_vertical"
- >
- <TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- />
- <TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:singleLine="true"
- android:gravity="center"
- android:paddingStart="8dp"
- />
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
- </LinearLayout>
- </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_base.xml b/core/res/res/layout/notification_template_quantum_base.xml
index 8f3019d..789bf32 100644
--- a/core/res/res/layout/notification_template_quantum_base.xml
+++ b/core/res/res/layout/notification_template_quantum_base.xml
@@ -23,10 +23,9 @@
internal:layout_minHeight="64dp"
internal:layout_maxHeight="64dp"
>
- <ImageView android:id="@+id/icon"
+ <include layout="@layout/notification_template_icon_group"
android:layout_width="@dimen/notification_large_icon_width"
android:layout_height="@dimen/notification_large_icon_height"
- android:scaleType="center"
/>
<LinearLayout
android:layout_width="match_parent"
@@ -91,7 +90,7 @@
android:layout_height="12dp"
android:layout_marginStart="8dp"
android:visibility="gone"
- style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
+ style="@style/Widget.StatusBar.Quantum.ProgressBar"
/>
<LinearLayout
android:id="@+id/line3"
@@ -121,16 +120,6 @@
android:gravity="center"
android:paddingStart="8dp"
/>
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
</LinearLayout>
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_big_base.xml b/core/res/res/layout/notification_template_quantum_big_base.xml
index 45e69b1..8cb5549 100644
--- a/core/res/res/layout/notification_template_quantum_big_base.xml
+++ b/core/res/res/layout/notification_template_quantum_big_base.xml
@@ -23,10 +23,9 @@
internal:layout_minHeight="65dp"
internal:layout_maxHeight="unbounded"
>
- <ImageView android:id="@+id/icon"
+ <include layout="@layout/notification_template_icon_group"
android:layout_width="@dimen/notification_large_icon_width"
android:layout_height="@dimen/notification_large_icon_height"
- android:scaleType="center"
/>
<LinearLayout
android:layout_width="match_parent"
@@ -128,16 +127,6 @@
android:gravity="center"
android:paddingStart="8dp"
/>
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
</LinearLayout>
<ProgressBar
android:id="@android:id/progress"
diff --git a/core/res/res/layout/notification_template_quantum_big_text.xml b/core/res/res/layout/notification_template_quantum_big_text.xml
index f7769d7..bbd1071 100644
--- a/core/res/res/layout/notification_template_quantum_big_text.xml
+++ b/core/res/res/layout/notification_template_quantum_big_text.xml
@@ -22,10 +22,9 @@
internal:layout_minHeight="65dp"
internal:layout_maxHeight="unbounded"
>
- <ImageView android:id="@+id/icon"
+ <include layout="@layout/notification_template_icon_group"
android:layout_width="@dimen/notification_large_icon_width"
android:layout_height="@dimen/notification_large_icon_height"
- android:scaleType="center"
/>
<LinearLayout
android:layout_width="match_parent"
@@ -166,16 +165,6 @@
android:gravity="center"
android:paddingStart="8dp"
/>
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
</LinearLayout>
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_inbox.xml b/core/res/res/layout/notification_template_quantum_inbox.xml
index 04974c4..a071d59 100644
--- a/core/res/res/layout/notification_template_quantum_inbox.xml
+++ b/core/res/res/layout/notification_template_quantum_inbox.xml
@@ -23,10 +23,9 @@
internal:layout_minHeight="65dp"
internal:layout_maxHeight="unbounded"
>
- <ImageView android:id="@+id/icon"
+ <include layout="@layout/notification_template_icon_group"
android:layout_width="@dimen/notification_large_icon_width"
android:layout_height="@dimen/notification_large_icon_height"
- android:scaleType="center"
/>
<LinearLayout
android:layout_width="match_parent"
@@ -250,16 +249,6 @@
android:gravity="center"
android:paddingStart="8dp"
/>
- <ImageView android:id="@+id/right_icon"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:layout_gravity="center"
- android:layout_weight="0"
- android:layout_marginStart="8dp"
- android:scaleType="centerInside"
- android:visibility="gone"
- android:drawableAlpha="153"
- />
</LinearLayout>
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index eb237b3..8bf8416 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -20,7 +20,7 @@
<com.android.internal.widget.ActionBarOverlayLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/action_bar_overlay_layout"
+ android:id="@+id/decor_content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:splitMotionEvents="false"
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index b3db01a..dc78174 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -22,7 +22,7 @@
android:layout_height="wrap_content"
android:background="#FFFF00FF"
>
- <include layout="@layout/notification_template_base"
+ <include layout="@layout/notification_template_quantum_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1d35c84..9fba1bf 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -355,10 +355,6 @@
when there is not reserved space for their UI (such as an Action Bar). -->
<attr name="windowActionModeOverlay" format="boolean" />
- <!-- Flag indicating that the action bar should be split to provide more
- room for elements. -->
- <attr name="windowSplitActionBar" format="boolean" />
-
<!-- Defines the default soft input state that this window would
like when it is displayed. Corresponds
to {@link android.view.WindowManager.LayoutParams#softInputMode}. -->
@@ -1672,6 +1668,7 @@
<enum name="KEYCODE_MEDIA_AUDIO_TRACK" value="222" />
<enum name="KEYCODE_MEDIA_SLEEP" value="223" />
<enum name="KEYCODE_MEDIA_WAKEUP" value="224" />
+ <enum name="KEYCODE_PAIRING" value="225" />
</attr>
<!-- ***************************************************************** -->
@@ -1704,7 +1701,6 @@
<attr name="windowActionBar" />
<attr name="windowActionModeOverlay" />
<attr name="windowActionBarOverlay" />
- <attr name="windowSplitActionBar" />
<attr name="windowEnableSplitTouch" />
<attr name="windowCloseOnTouchOutside" />
<attr name="windowTranslucentStatus" />
@@ -6343,8 +6339,9 @@
<!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that
describes a {@link android.service.voice.VoiceInteractionService}, which is referenced from
its {@link android.service.voice.VoiceInteractionService#SERVICE_META_DATA} meta-data entry.
- Described here are the attributes that can be included in that tag. -->
+ Described here are the attributes that can be included in that tag. @hide -->
<declare-styleable name="VoiceInteractionService">
+ <!-- @hide -->
<attr name="sessionService" format="string" />
<attr name="settingsActivity" />
</declare-styleable>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 69b11cd..52b021f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -227,9 +227,9 @@
<dimen name="action_bar_stacked_tab_max_width">180dp</dimen>
<!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
- <dimen name="notification_text_size">14dp</dimen>
+ <dimen name="notification_text_size">13dp</dimen>
<!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
- <dimen name="notification_title_text_size">18dp</dimen>
+ <dimen name="notification_title_text_size">16dp</dimen>
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
<dimen name="notification_subtext_size">12dp</dimen>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 891265f..fd57c5e 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -280,28 +280,28 @@
<style name="TextAppearance.StatusBar.Quantum">
</style>
<style name="TextAppearance.StatusBar.Quantum.EventContent">
- <item name="android:textColor">#888888</item>
+ <item name="android:textColor">#90000000</item>
<item name="android:textSize">@dimen/notification_text_size</item>
</style>
<style name="TextAppearance.StatusBar.Quantum.EventContent.Title">
- <item name="android:textColor">#000000</item>
- <item name="android:fontFamily">sans-serif-light</item>
+ <item name="android:textColor">#DD000000</item>
<item name="android:textSize">@dimen/notification_title_text_size</item>
- <item name="android:textStyle">bold</item>
</style>
<style name="TextAppearance.StatusBar.Quantum.EventContent.Line2">
<item name="android:textSize">@dimen/notification_subtext_size</item>
</style>
<style name="TextAppearance.StatusBar.Quantum.EventContent.Info">
<item name="android:textSize">@dimen/notification_subtext_size</item>
- <item name="android:textColor">#888888</item>
</style>
<style name="TextAppearance.StatusBar.Quantum.EventContent.Time">
<item name="android:textSize">@dimen/notification_subtext_size</item>
- <item name="android:textColor">#888888</item>
</style>
<style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis">
- <item name="android:textColor">#555555</item>
+ <item name="android:textColor">#66000000</item>
+ </style>
+
+ <style name="Widget.StatusBar.Quantum.ProgressBar"
+ parent="Widget.Quantum.Light.ProgressBar.Horizontal">
</style>
<style name="TextAppearance.Small.CalendarViewWeekDayView">
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index a49b89a..d04bddf 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -427,7 +427,10 @@
<item name="paddingEnd">8dp</item>
</style>
- <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView"/>
+ <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView">
+ <item name="drawablePadding">4dip</item>
+ </style>
+
<style name="Widget.Quantum.TextSelectHandle" parent="Widget.TextSelectHandle"/>
<style name="Widget.Quantum.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow"/>
<style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
@@ -441,10 +444,12 @@
<style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
<item name="background">?attr/selectableItemBackground</item>
+ <item name="drawablePadding">4dip</item>
</style>
<style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
<item name="background">?attr/selectableItemBackground</item>
+ <item name="drawablePadding">4dip</item>
</style>
<style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 84c9023..2d60b86 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -31,7 +31,6 @@
<java-symbol type="id" name="account_type" />
<java-symbol type="id" name="action_bar" />
<java-symbol type="id" name="action_bar_container" />
- <java-symbol type="id" name="action_bar_overlay_layout" />
<java-symbol type="id" name="action_bar_title" />
<java-symbol type="id" name="action_bar_subtitle" />
<java-symbol type="id" name="action_context_bar" />
@@ -61,6 +60,7 @@
<java-symbol type="id" name="day" />
<java-symbol type="id" name="day_names" />
<java-symbol type="id" name="decrement" />
+ <java-symbol type="id" name="decor_content_parent" />
<java-symbol type="id" name="default_activity_button" />
<java-symbol type="id" name="deny_button" />
<java-symbol type="id" name="description" />
@@ -1209,16 +1209,7 @@
<java-symbol type="layout" name="zoom_container" />
<java-symbol type="layout" name="zoom_controls" />
<java-symbol type="layout" name="zoom_magnify" />
- <java-symbol type="layout" name="notification_action" />
- <java-symbol type="layout" name="notification_action_tombstone" />
<java-symbol type="layout" name="notification_intruder_content" />
- <java-symbol type="layout" name="notification_template_base" />
- <java-symbol type="layout" name="notification_template_big_base" />
- <java-symbol type="layout" name="notification_template_big_picture" />
- <java-symbol type="layout" name="notification_template_big_text" />
- <java-symbol type="layout" name="notification_template_part_time" />
- <java-symbol type="layout" name="notification_template_part_chronometer" />
- <java-symbol type="layout" name="notification_template_inbox" />
<java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
<java-symbol type="layout" name="action_bar_up_container" />
<java-symbol type="layout" name="app_not_authorized" />
@@ -1667,8 +1658,10 @@
<java-symbol type="layout" name="notification_template_quantum_big_picture" />
<java-symbol type="layout" name="notification_template_quantum_big_text" />
<java-symbol type="layout" name="notification_template_quantum_inbox" />
+ <java-symbol type="layout" name="notification_template_icon_group" />
<java-symbol type="color" name="notification_action_legacy_color_filter" />
<java-symbol type="color" name="notification_icon_bg_color" />
+ <java-symbol type="drawable" name="notification_icon_legacy_bg" />
<java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
<java-symbol type="drawable" name="notification_quantum_bg_dim" />
<java-symbol type="drawable" name="notification_quantum_bg" />
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 45e2ab2..aab1e38 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -40,10 +40,11 @@
<h2 id="CreateDirs">Create Locale Directories and String Files</h2>
<p>To add support for more languages, create additional <code>values</code> directories inside
-<code>res/</code> that include a hyphen and the ISO country code at the end of the
+<code>res/</code> that include a hyphen and the ISO language code at the end of the
directory name. For example, <code>values-es/</code> is the directory containing simple
resourcess for the Locales with the language code "es". Android loads the appropriate resources
-according to the locale settings of the device at run time.</p>
+according to the locale settings of the device at run time. For more information, see
+ <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing Alternative Resources</a>.</p>
<p>Once you’ve decided on the languages you will support, create the resource subdirectories and
string resource files. For example:</p>
diff --git a/docs/html/wear/css/wear.css b/docs/html/wear/css/wear.css
index 40afeaa..fe9eef2 100644
--- a/docs/html/wear/css/wear.css
+++ b/docs/html/wear/css/wear.css
@@ -145,7 +145,7 @@
.wear-hero {
height: calc(100% - 70px);
min-height: 504px;
- margin-top: -4px;
+ margin-top: 0;
padding-top: 0;
padding-bottom: 0;
background-image: url(/wear/images/hero.jpg);
diff --git a/docs/html/wear/notifications/creating.jd b/docs/html/wear/notifications/creating.jd
index ce9e117..a5d7da7 100644
--- a/docs/html/wear/notifications/creating.jd
+++ b/docs/html/wear/notifications/creating.jd
@@ -44,8 +44,8 @@
you should include the following imports in your project code:</p>
<pre>
-import android.preview.support.wearable.notifications.*;
-import android.preview.support.v4.app.NotificationManagerCompat;
+import android.support.wearable.notifications.*;
+import android.support.wearable.app.NotificationManagerCompat;
import android.support.v4.app.NotificationCompat;
</pre>
@@ -64,7 +64,7 @@
<p>For example, here's some code that creates and issues a notification using the
{@link android.support.v4.app.NotificationCompat} APIs combined with the new
-<a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html">
+<a href="{@docRoot}reference/android/support/wearable/app/NotificationManagerCompat.html">
<code>NotificationManagerCompat</code></a> API:</p>
@@ -206,54 +206,70 @@
you can add additional pages of content that users can view by swiping to the left, or add the ability
for users to deliver your app a text response using voice input.</p>
-<p>To use these new APIs, pass your instance of
-{@link android.support.v4.app.NotificationCompat.Builder} to the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#WearableNotifications.Builder(android.content.Context)"> <code>WearableNotifications.Builder()</code></a> constructor. You can then add new
-features to your notification using the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
- ><code>WearableNotifications.Builder</code></a> methods. For example:</p>
+<p>To use these new APIs:</p>
+
+<ol>
+ <li>Create an instance of
+{@link android.support.v4.app.NotificationCompat.Builder}, setting the
+desired properties for your notification.</li>
+ <li>Create a
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#WearableNotificationOptions.Builder(android.content.Context)"> <code>WearableNotificationOptions.Builder</code></a>, setting the wearable-specific options for the notication.</li>
+ <li>Call <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#WearableNotificationOptions.Builder#applyTo"><code>WearableNotificationOptions.Builder.applyTo()</code>
+ </a>, passing in the {@link android.support.v4.app.NotificationCompat.Builder}. This applies
+ the wearable options to the notification.</li>
+</ol>
+
+<p>
+For example, the following code calls the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setHintHideIcon(boolean)">
+ <code>setHintHideIcon()</code></a> method to remove the app icon from the notification card.
+</p>
<pre>
// Create a NotificationCompat.Builder for standard notification features
-NotificationCompat.Builder notificationBuilder =
- new NotificationCompat.Builder(mContext)
- .setContentTitle("New mail from " + sender.toString())
- .setContentText(subject)
- .setSmallIcon(R.drawable.new_mail);
-
-// Create a WearablesNotification.Builder to add special functionality for wearables
-Notification notification =
- new WearableNotifications.Builder(notificationBuilder)
- .setHintHideIcon(true)
- .build();
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
+ .setContentTitle("New mail from " + sender)
+ .setContentText(subject)
+ .setSmallIcon(R.drawable.new_mail);
+// Create a WearablesNotificationOptions.Builder to add functionality for wearables
+ Notification notif = new WearableNotificationOptions.Builder()
+ <b>.setHintHideIcon(true)</b>
+ .build()
+ .applyTo(builder); //apply wearable options to to the original notification
+ .build()
</pre>
-<p>The <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setBigActionIcon(int)">
- <code>setHintHideIcon()</code></a> method removes your app icon from the notification card.
- This method is just one example of new notification features available from the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
- ><code>WearableNotifications.Builder</code></a> class.</p>
+<p>The
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setHintHideIcon(boolean)">
+ <code>setHintHideIcon()</code></a> method is just one example of new notification features available with the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"
+ ><code>WearableNotificationOptions.Builder</code></a> class.
+</p>
-<p>When you want to deliver your notifications, be certain to always use the
- <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html">
- <code>NotificationManagerCompat</code></a> API:</p>
+
+<p>When you want to deliver your notifications, always use the
+ <a href="{@docRoot}reference/android/support/wearable/app/NotificationManagerCompat.html">
+ <code>NotificationManagerCompat</code></a> API instead of
+ {@link android.app.NotificationManager}:</p>
<pre>
// Get an instance of the NotificationManager service
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(this);
-// Build the notification and issues it with notification manager.
-notificationManager.notify(notificationId, notification);
+// Issue the notification with notification manager.
+notificationManager.notify(notificationId, notif);
</pre>
-<p>If you instead use the framework's {@link android.app.NotificationManager}, some
-features from <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a>
-will not work.</p>
+
+<p>If you use the framework's {@link android.app.NotificationManager}, some
+features from <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"><code>WearableNotificationOptions.Builder</code></a>
+do not work.</p>
+
<p>To continue enhancing your notifications for wearables using
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
- ><code>WearableNotifications.Builder</code></a> and other APIs in the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"
+ ><code>WearableNotificationOptions.Builder</code></a> and other APIs in the
preview support library, see the following developer guides:</p>
<dl>
diff --git a/docs/html/wear/notifications/pages.jd b/docs/html/wear/notifications/pages.jd
index 558f7b8..7d18b3f 100644
--- a/docs/html/wear/notifications/pages.jd
+++ b/docs/html/wear/notifications/pages.jd
@@ -15,14 +15,19 @@
<a href="{@docRoot}wear/design/index.html#NotificationPages">Design Principles of Android
Wear</a>.</p>
-
-<p>When creating a notification with multiple pages, start by creating the main notification
-(the first page) the way you'd like the notification to appear on a phone
-or tablet. Then, add pages one at a time with the
-<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPage(android.app.Notification)">
+<p>To create a notification with multiple pages:</p>
+<ol>
+ <li>Create the main notification (the first page) the way you'd like the notification to appear on a phone
+ or tablet.</li>
+ <li>Add pages one at a time with the
+<a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addPage(android.app.Notification)">
<code>addPage()</code></a> method, or add multiple pages in a {@link java.util.Collection} with the
-<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPages(java.util.Collection<android.app.Notification>)">
-<code>addPages()</code></a> method.</p>
+<a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addPages(java.util.Collection<android.app.Notification>)">
+<code>addPages()</code></a> method.</li>
+ <li>Apply the pages to the main notification with the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.html#applyTo(android.support.v4.app.NotificationCompat.Builder)"
+ ><code>applyTo()</code></a> method.</li>
+</ol>
<p>For example, here's some code that adds a second page to a notification:</p>
@@ -47,15 +52,14 @@
.setStyle(secondPageStyle)
.build();
-// Create main notification and add the second page
+// Add second page with wearable options and apply to main notification
Notification twoPageNotification =
- new WearableNotifications.Builder(notificationBuilder)
+ new WearableNotificationsOptions.Builder()
.addPage(secondPageNotification)
+ .build()
+ .applyTo(notificationBuilder)
.build();
</pre>
-
-
-
</body>
</html>
diff --git a/docs/html/wear/notifications/remote-input.jd b/docs/html/wear/notifications/remote-input.jd
index 1668363..4db8274 100644
--- a/docs/html/wear/notifications/remote-input.jd
+++ b/docs/html/wear/notifications/remote-input.jd
@@ -25,16 +25,16 @@
<h2 id="RemoteInput">Define the Remote Input</h2>
<p>To create an action that supports voice input, first create an instance of
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html">
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html">
<code>RemoteInput</code></a> using the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> APIs.
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> APIs.
The
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor takes a string that the system
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor takes a string that the system
will use as a key for the {@link android.content.Intent} extra that carries the reply message
to your app on the handheld.</p>
<p>For example, here's how to create a new
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html">
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html">
<code>RemoteInput</code></a> object that provides a custom
label for the voice input prompt:</p>
@@ -56,7 +56,7 @@
<p>In addition to allowing voice input, you can
provide up to five text responses that the user can select for quick replies. Call
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html#setChoices(java.lang.String[])"><code>setChoices()</code></a> and pass it a string array.</p>
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html#setChoices(java.lang.String[])"><code>setChoices()</code></a> and pass it a string array.</p>
<p>For example, you may define some responses in a resource array:</p>
@@ -73,7 +73,7 @@
</pre>
<p>Then, inflate the string array and add it to the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a>:</p>
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a>:</p>
<pre>
String replyLabel = getResources().getString(R.string.reply_label);
@@ -93,8 +93,8 @@
<p>If "Reply" is your notification's primary action (defined by the {@link
android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}
method), then you should attach the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the main action using
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the main action using
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addRemoteInputForContentIntent(android.support.wearable.notifications.RemoteInput)">
<code>addRemoteInputForContentIntent()</code></a>. For example:</p>
<pre>
@@ -116,18 +116,19 @@
.setLabel(replyLabel)
.build();
-// Create wearable notification and add remote input
+// Add remote input to wearable options and apply to notification
Notification replyNotification =
- new WearableNotifications.Builder(replyNotificationBuilder)
+ new WearableNotificationOptions.Builder()
.addRemoteInputForContentIntent(remoteInput)
+ .build()
+ .applyTo(replyNotificationBuilder)
.build();
</pre>
-
<p>By using
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#addRemoteInputForContentIntent(android.support.wearable.notifications.RemoteInput)">
<code>addRemoteInputForContentIntent()</code></a> to add the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> object to the notification's primary action,
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> object to the notification's primary action,
the button that normally appears as an "Open" action becomes the "Reply" action
and starts the voice input UI when users select it on Android Wear.</p>
@@ -137,14 +138,14 @@
<p>If the "Reply" action is not your notification's primary action and you want to enable
voice input for a secondary action, add the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to a new action button defined by an
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to a new action button defined by an
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
<code>Action</code></a> object.</p>
<p>You should instantiate the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a> with the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html"><code>Action.Builder()</code></a>
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
+<code>WearableAction</code></a> with the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.Builder.html"><code>WearableAction.Builder()</code></a>
constructor, which takes an icon and text label for the action button, plus the
{@link android.app.PendingIntent}
the system should use to invoke your app when the user selects the action. For example:</p>
@@ -161,7 +162,7 @@
.build();
// Create the notification action
-Action replyAction = new Action.Builder(R.drawable.ic_message,
+WearableAction replyAction = new WearableAction.Builder(R.drawable.ic_message,
"Reply", pendingIntent)
.addRemoteInput(remoteInput)
.build();
@@ -169,45 +170,72 @@
<p>After you add the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a>, add the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a> to the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a> using
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addAction(Action)"><code>addAction()</code></a>.
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
+<code>Wearablection</code></a>, set the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableAction.html">
+<code>WearableAction</code></a> on the
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html"><code>WearableNotifications.Builder</code></a> using
+ <a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationsOptions.Builder.html#addAction(Action)"><code>addAction()</code></a>.
For example:</p>
<pre>
// Create basic notification builder
NotificationCompat.Builder replyNotificationBuilder =
new NotificationCompat.Builder(this)
- .setContentTitle("New message");
+ .setContentTitle("New message");
// Create the notification action and add remote input
-Action replyAction = new Action.Builder(R.drawable.ic_message,
+WearableAction replyAction = new WearableAction.Builder(R.drawable.ic_message,
"Reply", pendingIntent)
.addRemoteInput(remoteInput)
.build();
// Create wearable notification and add action
Notification replyNotification =
- new WearableNotifications.Builder(replyNotificationBuilder)
- .addAction(replyAction)
- .build();
+ new WearableNotificationOptions.Builder()
+ .addAction(replyAction)
+ .build()
+ .applyTo(replyNotificationBuilder)
+ .build();
</pre>
+
<p>Now, when the user selects "Reply" from an Android wearable, the system prompts the user
for voice input (and shows the list of pre-defined replies, if provided).
Once the user completes a response, the system invokes
the {@link android.content.Intent} attached to the action and adds the
<code>EXTRA_VOICE_REPLY</code> extra (the string
you passed to the
- <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor)
- with the user's message as the string value.</p>
+ <a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor)
+ with the user's message as the string value.</p>
-
-
+<h2 id="ObtainInput">Obtaining the Voice Input as a String</h2>
+<p>To obtain the user's voice input, call
+<a href="{@docRoot}reference/android/support/wearable/notifications/RemoteInput.html#getResultsFromIntent(Intent)"><code>getResultsFromIntent()</code></a>,
+passing in the "Reply" action's intent. This method returns
+a {@link android.os.Bundle} that represents the intent's extras. You can then query the
+{@link android.os.Bundle} to obtain the user's voice input string.
+</p>
+<p>
+The following code shows a method that accepts an intent and returns the voice input string,
+which is referenced by the <code>EXTRA_VOICE_REPLY</code> key that is used in the previous examples:
+</p>
+<pre>
+/**
+ * Obtain the intent that started this activity by calling
+ * Activity.getIntent() and pass it into this method to
+ * get the associated voice input string.
+ */
+private String getMessageText(Intent intent) {
+ Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
+ if (remoteInput != null) {
+ return remoteInput.getString(Intent.EXTRA_VOICE_REPLY);
+ }
+ }
+ return null;
+}
+</pre>
</body>
</html>
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index a2d34ce..3c3dc09 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -16,7 +16,7 @@
handheld to view more information). So for the wearable device, you should
group all the notifications together in a stack. The stack of notifications appears as a single
card, which users can expand to view the details from each notification separately. The new
-<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+<a href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setGroup(java.lang.String, int)">
<code>setGroup()</code></a> method makes this possible while allowing you to still provide
only one summary notification on the handheld device.</p>
@@ -28,21 +28,24 @@
<h2 id="AddGroup">Add Each Notification to a Group</h2>
<p>To create a stack, call <a
-href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setGroup(java.lang.String, int)">
<code>setGroup()</code></a> for each notification you want in the stack and specify a
-group key. Then call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
+group key. Then call <a href="{@docRoot}reference/android/support/wearable/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
<pre style="clear:right">
final static String GROUP_KEY_EMAILS = "group_key_emails";
-// Build the notification and pass this builder to WearableNotifications.Builder
+// Build the notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
.setContentTitle("New mail from " + sender1)
.setContentText(subject1)
.setSmallIcon(R.drawable.new_mail);
-Notification notif1 = new WearableNotifications.Builder(builder)
+// Set the group with WearableNotificationOptions.Builder and apply to the notification
+Notification notif1 = new WearableNotificationOptions.Builder()
.setGroup(GROUP_KEY_EMAILS)
+ .build()
+ .applyTo(builder)
.build();
// Issue the notification
@@ -52,8 +55,10 @@
</pre>
<p>Later on, when you create another notification, specify
-the same group key. When you call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>, this notification appears
-in the same stack as the previous notification, instead of as a new card:</p>
+the same group key. When you call
+<a href="{@docRoot}reference/android/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>,
+this notification appears in the same stack as the previous notification,
+instead of as a new card:</p>
<pre style="clear:right">
builder = new NotificationCompat.Builder(mContext)
@@ -62,8 +67,10 @@
.setSmallIcon(R.drawable.new_mail);
// Use the same group as the previous notification
-Notification notif2 = new WearableNotifications.Builder(builder)
+Notification notif2 = new WearableNotificationOptions.Builder()
.setGroup(GROUP_KEY_EMAILS)
+ .build()
+ .applyTo(builder)
.build();
notificationManager.notify(notificationId2, notif);
@@ -72,7 +79,7 @@
<p>By default, notifications appear in the order in which you added them, with the most recent
notification visible at the top. You can define a specific position in the group
by passing an order position as the second parameter for <a
-href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationOptions.Builder.html#setGroup(java.lang.String, int)">
<code>setGroup()</code></a>.</p>
@@ -83,7 +90,7 @@
<p>It's important that you still provide a summary notification that appears on handheld devices.
So in addition to adding each unique notification to the same stack group, also add a summary
notification, but set its order position to be <a
-href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
+href="{@docRoot}reference/android/support/wearable/notifications/WearableNotificationsOptions.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
<p>This notification does not appear in your stack of notifications on the wearable, but
appears as the only notification on the handheld device.</p>
@@ -92,23 +99,22 @@
Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_large_icon);
+// Create an InboxStyle notification
builder = new NotificationCompat.Builder(this)
+ .setContentTitle("2 new messages")
.setSmallIcon(R.drawable.ic_small_icon)
- .setLargeIcon(largeIcon);
+ .setLargeIcon(largeIcon)
+ .setStyle(new NotificationCompat.InboxStyle()
+ .addLine("Alex Faaborg Check this out")
+ .addLine("Jeff Chang Launch Party")
+ .setBigContentTitle("2 new messages")
+ .setSummaryText("johndoe@gmail.com"));
-// Use the same group key and pass this builder to InboxStyle notification
-WearableNotifications.Builder wearableBuilder = new WearableNotifications
- .Builder(builder)
- .setGroup(GROUP_KEY_EMAILS,
- WearableNotifications.GROUP_ORDER_SUMMARY);
-
-// Build the final notification to show on the handset
-Notification summaryNotification = new NotificationCompat.InboxStyle(
- wearableBuilder.getCompatBuilder())
- .addLine("Alex Faaborg Check this out")
- .addLine("Jeff Chang Launch Party")
- .setBigContentTitle("2 new messages")
- .setSummaryText("johndoe@gmail.com")
+// Specify the notification to be the group summary
+Notification summaryNotification = new WearableNotificationOptions.Builder()
+ .setGroupSummary(GROUP_KEY_EMAILS)
+ .build()
+ .applyTo(builder)
.build();
notificationManager.notify(notificationId3, summaryNotification);
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 218a057..24e8de6 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -17,227 +17,220 @@
package android.graphics.drawable;
import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
-import android.view.animation.DecelerateInterpolator;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.animation.AccelerateInterpolator;
+
+import java.util.ArrayList;
/**
* Draws a Quantum Paper ripple.
*/
class Ripple {
- private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator();
+ private static final TimeInterpolator INTERPOLATOR = new AccelerateInterpolator();
- /** Starting radius for a ripple. */
- private static final int STARTING_RADIUS_DP = 16;
+ private static final float GLOBAL_SPEED = 1.0f;
+ private static final float WAVE_TOUCH_DOWN_ACCELERATION = 512.0f * GLOBAL_SPEED;
+ private static final float WAVE_TOUCH_UP_ACCELERATION = 1024.0f * GLOBAL_SPEED;
+ private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.6f / GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED;
- /** Radius when finger is outside view bounds. */
- private static final int OUTSIDE_RADIUS_DP = 16;
-
- /** Radius when finger is inside view bounds. */
- private static final int INSIDE_RADIUS_DP = 96;
-
- /** Margin when constraining outside touches (fraction of outer radius). */
- private static final float OUTSIDE_MARGIN = 0.8f;
-
- /** Resistance factor when constraining outside touches. */
- private static final float OUTSIDE_RESISTANCE = 0.7f;
-
- /** Minimum alpha value during a pulse animation. */
- private static final float PULSE_MIN_ALPHA = 0.5f;
-
- /** Duration for animating the trailing edge of the ripple. */
- private static final int EXIT_DURATION = 600;
-
- /** Duration for animating the leading edge of the ripple. */
- private static final int ENTER_DURATION = 400;
-
- /** Duration for animating the ripple alpha in and out. */
- private static final int FADE_DURATION = 50;
-
- /** Minimum elapsed time between start of enter and exit animations. */
- private static final int EXIT_MIN_DELAY = 200;
-
- /** Duration for animating between inside and outside touch. */
- private static final int OUTSIDE_DURATION = 300;
-
- /** Duration for animating pulses. */
- private static final int PULSE_DURATION = 400;
-
- /** Interval between pulses while inside and fully entered. */
- private static final int PULSE_INTERVAL = 400;
-
- /** Delay before pulses start. */
- private static final int PULSE_DELAY = 500;
+ // Hardware animators.
+ private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
+ private final ArrayList<RenderNodeAnimator> mPendingAnimations = new ArrayList<>();
private final Drawable mOwner;
- /** Bounds used for computing max radius and containment. */
+ /** Bounds used for computing max radius. */
private final Rect mBounds;
- /** Configured maximum ripple radius when the center is outside the bounds. */
- private final int mMaxOutsideRadius;
-
- /** Configured maximum ripple radius. */
- private final int mMaxInsideRadius;
-
- private ObjectAnimator mOuter;
- private ObjectAnimator mInner;
- private ObjectAnimator mAlpha;
+ /** Full-opacity color for drawing this ripple. */
+ private final int mColor;
/** Maximum ripple radius. */
- private int mMaxRadius;
-
private float mOuterRadius;
- private float mInnerRadius;
- private float mAlphaMultiplier;
- /** Center x-coordinate. */
+ // Hardware rendering properties.
+ private CanvasProperty<Paint> mPropPaint;
+ private CanvasProperty<Float> mPropRadius;
+ private CanvasProperty<Float> mPropX;
+ private CanvasProperty<Float> mPropY;
+ private CanvasProperty<Paint> mPropOuterPaint;
+ private CanvasProperty<Float> mPropOuterRadius;
+ private CanvasProperty<Float> mPropOuterX;
+ private CanvasProperty<Float> mPropOuterY;
+
+ // Software animators.
+ private ObjectAnimator mAnimRadius;
+ private ObjectAnimator mAnimOpacity;
+ private ObjectAnimator mAnimOuterOpacity;
+ private ObjectAnimator mAnimX;
+ private ObjectAnimator mAnimY;
+
+ // Software rendering properties.
+ private float mOuterOpacity = 0;
+ private float mOpacity = 1;
+ private float mRadius = 0;
+ private float mOuterX;
+ private float mOuterY;
private float mX;
-
- /** Center y-coordinate. */
private float mY;
- /** Whether the center is within the parent bounds. */
- private boolean mInsideBounds;
+ private boolean mFinished;
- /** Whether to pulse this ripple. */
- private boolean mPulseEnabled;
+ /** Whether we should be drawing hardware animations. */
+ private boolean mHardwareAnimating;
- /** Temporary hack since we can't check finished state of animator. */
- private boolean mExitFinished;
-
- /** Whether this ripple has ever moved. */
- private boolean mHasMoved;
+ /** Whether we can use hardware acceleration for the exit animation. */
+ private boolean mCanUseHardware;
/**
* Creates a new ripple.
*/
- public Ripple(Drawable owner, Rect bounds, float density, boolean pulseEnabled) {
+ public Ripple(Drawable owner, Rect bounds, int color) {
mOwner = owner;
mBounds = bounds;
- mPulseEnabled = pulseEnabled;
+ mColor = color | 0xFF000000;
- mOuterRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
- mMaxOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
- mMaxInsideRadius = (int) (density * INSIDE_RADIUS_DP + 0.5f);
- mMaxRadius = Math.min(mMaxInsideRadius, Math.max(bounds.width(), bounds.height()));
+ final float halfWidth = bounds.width() / 2.0f;
+ final float halfHeight = bounds.height() / 2.0f;
+ mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+ mOuterX = 0;
+ mOuterY = 0;
}
- public void setOuterRadius(float r) {
- mOuterRadius = r;
+ public void setRadius(float r) {
+ mRadius = r;
invalidateSelf();
}
- public float getOuterRadius() {
- return mOuterRadius;
+ public float getRadius() {
+ return mRadius;
}
- public void setInnerRadius(float r) {
- mInnerRadius = r;
+ public void setOpacity(float a) {
+ mOpacity = a;
invalidateSelf();
}
- public float getInnerRadius() {
- return mInnerRadius;
+ public float getOpacity() {
+ return mOpacity;
}
- public void setAlphaMultiplier(float a) {
- mAlphaMultiplier = a;
+ public void setOuterOpacity(float a) {
+ mOuterOpacity = a;
invalidateSelf();
}
- public float getAlphaMultiplier() {
- return mAlphaMultiplier;
+ public float getOuterOpacity() {
+ return mOuterOpacity;
+ }
+
+ public void setX(float x) {
+ mX = x;
+ invalidateSelf();
+ }
+
+ public float getX() {
+ return mX;
+ }
+
+ public void setY(float y) {
+ mY = y;
+ invalidateSelf();
+ }
+
+ public float getY() {
+ return mY;
}
/**
* Returns whether this ripple has finished exiting.
*/
public boolean isFinished() {
- return mExitFinished;
+ return mFinished;
}
/**
- * Called when the bounds change.
- */
- public void onBoundsChanged() {
- mMaxRadius = Math.min(mMaxInsideRadius, Math.max(mBounds.width(), mBounds.height()));
-
- updateInsideBounds();
- }
-
- private void updateInsideBounds() {
- final boolean insideBounds = mBounds.contains((int) (mX + 0.5f), (int) (mY + 0.5f));
- if (mInsideBounds != insideBounds || !mHasMoved) {
- mInsideBounds = insideBounds;
- mHasMoved = true;
-
- if (insideBounds) {
- enter();
- } else {
- outside();
- }
- }
- }
-
- /**
- * Draws the ripple using the specified paint.
+ * Draws the ripple centered at (0,0) using the specified paint.
*/
public boolean draw(Canvas c, Paint p) {
- final Rect bounds = mBounds;
- final float outerRadius = mOuterRadius;
- final float innerRadius = mInnerRadius;
- final float alphaMultiplier = mAlphaMultiplier;
+ final boolean canUseHardware = c.isHardwareAccelerated();
+ if (mCanUseHardware != canUseHardware && mCanUseHardware) {
+ // We've switched from hardware to non-hardware mode. Panic.
+ cancelHardwareAnimations();
+ }
+ mCanUseHardware = canUseHardware;
+
+ final boolean hasContent;
+ if (canUseHardware && mHardwareAnimating) {
+ hasContent = drawHardware((HardwareCanvas) c);
+ } else {
+ hasContent = drawSoftware(c, p);
+ }
+
+ return hasContent;
+ }
+
+ private boolean drawHardware(HardwareCanvas c) {
+ // If we have any pending hardware animations, cancel any running
+ // animations and start those now.
+ final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
+ final int N = pendingAnimations == null ? 0 : pendingAnimations.size();
+ if (N > 0) {
+ cancelHardwareAnimations();
+
+ for (int i = 0; i < N; i++) {
+ pendingAnimations.get(i).setTarget(c);
+ pendingAnimations.get(i).start();
+ }
+
+ mRunningAnimations.addAll(pendingAnimations);
+ pendingAnimations.clear();
+ }
+
+ c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
+ c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+
+ return true;
+ }
+
+ private boolean drawSoftware(Canvas c, Paint p) {
+ final float radius = mRadius;
+ final float opacity = mOpacity;
+ final float outerOpacity = mOuterOpacity;
// Cache the paint alpha so we can restore it later.
final int paintAlpha = p.getAlpha();
- final int alpha = (int) (paintAlpha * alphaMultiplier + 0.5f);
+ final int alpha = (int) (255 * opacity + 0.5f);
+ final int outerAlpha = (int) (255 * outerOpacity + 0.5f);
- // Apply resistance effect when outside bounds.
- final float x;
- final float y;
- if (mInsideBounds) {
- x = mX;
- y = mY;
- } else {
- // TODO: We need to do this outside of draw() so that our dirty
- // bounds accurately reflect resistance.
- x = looseConstrain(mX, bounds.left, bounds.right,
- mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
- y = looseConstrain(mY, bounds.top, bounds.bottom,
- mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+ boolean hasContent = false;
+
+ if (outerAlpha > 0 && alpha > 0) {
+ p.setAlpha(Math.min(alpha, outerAlpha));
+ p.setStyle(Style.FILL);
+ c.drawCircle(mOuterX, mOuterY, mOuterRadius, p);
+ hasContent = true;
}
- final boolean hasContent;
- if (alphaMultiplier <= 0 || innerRadius >= outerRadius) {
- // Nothing to draw.
- hasContent = false;
- } else if (innerRadius > 0) {
- // Draw a ring.
- final float strokeWidth = outerRadius - innerRadius;
- final float strokeRadius = innerRadius + strokeWidth / 2.0f;
- p.setAlpha(alpha);
- p.setStyle(Style.STROKE);
- p.setStrokeWidth(strokeWidth);
- c.drawCircle(x, y, strokeRadius, p);
- hasContent = true;
- } else if (outerRadius > 0) {
- // Draw a circle.
+ if (opacity > 0 && radius > 0) {
p.setAlpha(alpha);
p.setStyle(Style.FILL);
- c.drawCircle(x, y, outerRadius, p);
+ c.drawCircle(mX, mY, radius, p);
hasContent = true;
- } else {
- hasContent = false;
}
p.setAlpha(paintAlpha);
+
return hasContent;
}
@@ -245,156 +238,279 @@
* Returns the maximum bounds for this ripple.
*/
public void getBounds(Rect bounds) {
+ final int outerX = (int) mOuterX;
+ final int outerY = (int) mOuterY;
+ final int r = (int) mOuterRadius;
+ bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+
final int x = (int) mX;
final int y = (int) mY;
- final int maxRadius = mMaxRadius;
- bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+ bounds.union(x - r, y - r, x + r, y + r);
}
/**
- * Updates the center coordinates.
+ * Starts the enter animation at the specified absolute coordinates.
*/
- public void move(float x, float y) {
- mX = x;
- mY = y;
+ public void enter(float x, float y) {
+ mX = x - mBounds.exactCenterX();
+ mY = y - mBounds.exactCenterY();
- updateInsideBounds();
+ final int radiusDuration = (int)
+ (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION) + 0.5);
+ final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY);
+
+ final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", 0, mOuterRadius);
+ radius.setAutoCancel(true);
+ radius.setDuration(radiusDuration);
+
+ final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "x", mOuterX);
+ cX.setAutoCancel(true);
+ cX.setDuration(radiusDuration);
+
+ final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "y", mOuterY);
+ cY.setAutoCancel(true);
+ cY.setDuration(radiusDuration);
+
+ final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+ outer.setAutoCancel(true);
+ outer.setDuration(outerDuration);
+
+ mAnimRadius = radius;
+ mAnimOuterOpacity = outer;
+ mAnimX = cX;
+ mAnimY = cY;
+
+ // Enter animations always run on the UI thread, since it's unlikely
+ // that anything interesting is happening until the user lifts their
+ // finger.
+ radius.start();
+ outer.start();
+ cX.start();
+ cY.start();
+ }
+
+ /**
+ * Starts the exit animation.
+ */
+ public void exit() {
+ cancelSoftwareAnimations();
+
+ final float remaining;
+ if (mAnimRadius != null && mAnimRadius.isRunning()) {
+ remaining = mOuterRadius - mRadius;
+ } else {
+ remaining = mOuterRadius;
+ }
+
+ final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
+ + WAVE_TOUCH_DOWN_ACCELERATION)) + 0.5);
+ final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+
+ // Determine at what time the inner and outer opacity intersect.
+ // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
+ // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
+ final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
+ / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f));
+ final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
+ * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f);
+
+ if (mCanUseHardware) {
+ exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+ } else {
+ exitSoftware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+ }
+ }
+
+ private void exitHardware(int radiusDuration, int opacityDuration, int outerInflection,
+ int inflectionOpacity) {
+ mPendingAnimations.clear();
+
+ final Paint outerPaint = new Paint();
+ outerPaint.setAntiAlias(true);
+ outerPaint.setColor(mColor);
+ outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f));
+ outerPaint.setStyle(Style.FILL);
+ mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
+ mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
+ mPropOuterX = CanvasProperty.createFloat(mOuterX);
+ mPropOuterY = CanvasProperty.createFloat(mOuterY);
+
+ final Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(mColor);
+ paint.setAlpha((int) (255 * mOpacity + 0.5f));
+ paint.setStyle(Style.FILL);
+ mPropPaint = CanvasProperty.createPaint(paint);
+ mPropRadius = CanvasProperty.createFloat(mRadius);
+ mPropX = CanvasProperty.createFloat(mX);
+ mPropY = CanvasProperty.createFloat(mY);
+
+ final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mOuterRadius);
+ radius.setDuration(radiusDuration);
+
+ final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mOuterX);
+ x.setDuration(radiusDuration);
+
+ final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mOuterY);
+ y.setDuration(radiusDuration);
+
+ final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+ RenderNodeAnimator.PAINT_ALPHA, 0);
+ opacity.setDuration(opacityDuration);
+ opacity.addListener(mAnimationListener);
+
+ final RenderNodeAnimator outerOpacity;
+ if (outerInflection > 0) {
+ // Outer opacity continues to increase for a bit.
+ outerOpacity = new RenderNodeAnimator(
+ mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
+ outerOpacity.setDuration(outerInflection);
+
+ // Chain the outer opacity exit animation.
+ final int outerDuration = opacityDuration - outerInflection;
+ if (outerDuration > 0) {
+ final RenderNodeAnimator outerFadeOut = new RenderNodeAnimator(
+ mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+ outerFadeOut.setDuration(outerDuration);
+ outerFadeOut.setStartDelay(outerInflection);
+
+ mPendingAnimations.add(outerFadeOut);
+ }
+ } else {
+ outerOpacity = new RenderNodeAnimator(
+ mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+ outerOpacity.setDuration(opacityDuration);
+ }
+
+ mPendingAnimations.add(radius);
+ mPendingAnimations.add(opacity);
+ mPendingAnimations.add(outerOpacity);
+ mPendingAnimations.add(x);
+ mPendingAnimations.add(y);
+
+ mHardwareAnimating = true;
+
invalidateSelf();
}
- /**
- * Starts the exit animation. If {@link #enter()} was called recently, the
- * animation may be postponed.
- */
- public void exit() {
- mExitFinished = false;
+ private void exitSoftware(int radiusDuration, int opacityDuration, int outerInflection,
+ float inflectionOpacity) {
+ final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", mOuterRadius);
+ radius.setAutoCancel(true);
+ radius.setDuration(radiusDuration);
- final ObjectAnimator inner = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius);
- inner.setAutoCancel(true);
- inner.setDuration(EXIT_DURATION);
- inner.setInterpolator(INTERPOLATOR);
- inner.addListener(mAnimationListener);
+ final ObjectAnimator x = ObjectAnimator.ofFloat(this, "x", mOuterX);
+ x.setAutoCancel(true);
+ x.setDuration(radiusDuration);
- if (mOuter != null && mOuter.isStarted()) {
- // If we haven't been running the enter animation for long enough,
- // delay the exit animator.
- final int elapsed = (int) (mOuter.getAnimatedFraction() * mOuter.getDuration());
- final int delay = Math.max(0, EXIT_MIN_DELAY - elapsed);
- inner.setStartDelay(delay);
+ final ObjectAnimator y = ObjectAnimator.ofFloat(this, "y", mOuterY);
+ y.setAutoCancel(true);
+ y.setDuration(radiusDuration);
+
+ final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "opacity", 0);
+ opacity.setAutoCancel(true);
+ opacity.setDuration(opacityDuration);
+ opacity.addListener(mAnimationListener);
+
+ final ObjectAnimator outerOpacity;
+ if (outerInflection > 0) {
+ // Outer opacity continues to increase for a bit.
+ outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", inflectionOpacity);
+ outerOpacity.setDuration(outerInflection);
+
+ // Chain the outer opacity exit animation.
+ final int outerDuration = opacityDuration - outerInflection;
+ outerOpacity.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ final ObjectAnimator outerFadeOut = ObjectAnimator.ofFloat(Ripple.this,
+ "outerOpacity", 0);
+ outerFadeOut.setDuration(outerDuration);
+
+ mAnimOuterOpacity = outerFadeOut;
+
+ outerFadeOut.start();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ animation.removeListener(this);
+ }
+ });
+ } else {
+ outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0);
+ outerOpacity.setDuration(opacityDuration);
}
- inner.start();
+ mAnimRadius = radius;
+ mAnimOpacity = opacity;
+ mAnimOuterOpacity = outerOpacity;
+ mAnimX = opacity;
+ mAnimY = opacity;
- final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0);
- alpha.setAutoCancel(true);
- alpha.setDuration(EXIT_DURATION);
- alpha.start();
-
- mInner = inner;
- mAlpha = alpha;
+ radius.start();
+ opacity.start();
+ outerOpacity.start();
+ x.start();
+ y.start();
}
/**
* Cancel all animations.
*/
public void cancel() {
- if (mInner != null) {
- mInner.cancel();
+ cancelSoftwareAnimations();
+ cancelHardwareAnimations();
+ }
+
+ private void cancelSoftwareAnimations() {
+ if (mAnimRadius != null) {
+ mAnimRadius.cancel();
}
- if (mOuter != null) {
- mOuter.cancel();
+ if (mAnimOpacity != null) {
+ mAnimOpacity.cancel();
}
- if (mAlpha != null) {
- mAlpha.cancel();
+ if (mAnimOuterOpacity != null) {
+ mAnimOuterOpacity.cancel();
}
+
+ if (mAnimX != null) {
+ mAnimX.cancel();
+ }
+
+ if (mAnimY != null) {
+ mAnimY.cancel();
+ }
+ }
+
+ /**
+ * Cancels any running hardware animations.
+ */
+ private void cancelHardwareAnimations() {
+ final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+ final int N = runningAnimations == null ? 0 : runningAnimations.size();
+ for (int i = 0; i < N; i++) {
+ runningAnimations.get(i).cancel();
+ }
+
+ runningAnimations.clear();
}
private void invalidateSelf() {
mOwner.invalidateSelf();
}
- /**
- * Starts the enter animation.
- */
- private void enter() {
- final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius);
- outer.setAutoCancel(true);
- outer.setDuration(ENTER_DURATION);
- outer.setInterpolator(INTERPOLATOR);
- outer.start();
-
- final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
- if (mPulseEnabled) {
- alpha.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- final ObjectAnimator pulse = ObjectAnimator.ofFloat(
- this, "alphaMultiplier", 1, PULSE_MIN_ALPHA);
- pulse.setAutoCancel(true);
- pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL);
- pulse.setRepeatCount(ObjectAnimator.INFINITE);
- pulse.setRepeatMode(ObjectAnimator.REVERSE);
- pulse.setStartDelay(PULSE_DELAY);
- pulse.start();
-
- mAlpha = pulse;
- }
- });
- }
- alpha.setAutoCancel(true);
- alpha.setDuration(FADE_DURATION);
- alpha.start();
-
- mOuter = outer;
- mAlpha = alpha;
- }
-
- /**
- * Starts the outside transition animation.
- */
- private void outside() {
- final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxOutsideRadius);
- outer.setAutoCancel(true);
- outer.setDuration(OUTSIDE_DURATION);
- outer.setInterpolator(INTERPOLATOR);
- outer.start();
-
- final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
- alpha.setAutoCancel(true);
- alpha.setDuration(FADE_DURATION);
- alpha.start();
-
- mOuter = outer;
- mAlpha = alpha;
- }
-
- /**
- * Constrains a value within a specified asymptotic margin outside a minimum
- * and maximum.
- */
- private static float looseConstrain(float value, float min, float max, float margin,
- float factor) {
- // TODO: Can we use actual spring physics here?
- if (value < min) {
- return min - Math.min(margin, (float) Math.pow(min - value, factor));
- } else if (value > max) {
- return max + Math.min(margin, (float) Math.pow(value - max, factor));
- } else {
- return value;
- }
- }
-
- private final AnimatorListener mAnimationListener = new AnimatorListenerAdapter() {
+ private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- if (animation == mInner) {
- mExitFinished = true;
- mOuterRadius = 0;
- mInnerRadius = 0;
- mAlphaMultiplier = 1;
- }
+ mFinished = true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mFinished = true;
}
};
}
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 8128b5f..a55a4b2 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -24,6 +24,7 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
@@ -33,6 +34,7 @@
import android.util.SparseArray;
import com.android.internal.R;
+import com.android.org.bouncycastle.util.Arrays;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -40,11 +42,36 @@
import java.io.IOException;
/**
- * Documentation pending.
+ * Drawable that shows a ripple effect in response to state changes. The
+ * anchoring position of the ripple for a given state may be specified by
+ * calling {@link #setHotspot(int, float, float)} with the corresponding state
+ * attribute identifier.
+ * <p>
+ * A touch feedback drawable may contain multiple child layers, including a
+ * special mask layer that is not drawn to the screen. A single layer may be set
+ * as the mask by specifying its android:id value as {@link android.R.id#mask}.
+ * <p>
+ * If a mask layer is set, the ripple effect will be masked against that layer
+ * before it is blended onto the composite of the remaining child layers.
+ * <p>
+ * If no mask layer is set, the ripple effect is simply blended onto the
+ * composite of the child layers using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}.
+ * <p>
+ * If no child layers or mask is specified and the ripple is set as a View
+ * background, the ripple will be blended onto the first available parent
+ * background within the View's hierarchy using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}. In this case, the
+ * drawing region may extend outside of the Drawable bounds.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
*/
public class TouchFeedbackDrawable extends LayerDrawable {
private static final String LOG_TAG = TouchFeedbackDrawable.class.getSimpleName();
private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
+ private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
+ private static final PorterDuffXfermode SRC_ATOP = new PorterDuffXfermode(Mode.SRC_ATOP);
private static final PorterDuffXfermode SRC_OVER = new PorterDuffXfermode(Mode.SRC_OVER);
/** The maximum number of ripples supported. */
@@ -63,10 +90,22 @@
private final TouchFeedbackState mState;
- /** Lazily-created map of touch hotspot IDs to ripples. */
- private SparseArray<Ripple> mRipples;
+ /**
+ * Lazily-created map of pending hotspot locations. These may be modified by
+ * calls to {@link #setHotspot(int, float, float)}.
+ */
+ private SparseArray<PointF> mPendingHotspots;
- /** Lazily-created array of actively animating ripples. */
+ /**
+ * Lazily-created map of active hotspot locations. These may be modified by
+ * calls to {@link #setHotspot(int, float, float)}.
+ */
+ private SparseArray<Ripple> mActiveHotspots;
+
+ /**
+ * Lazily-created array of actively animating ripples. Inactive ripples are
+ * pruned during draw(). The locations of these will not change.
+ */
private Ripple[] mAnimatingRipples;
private int mAnimatingRipplesCount = 0;
@@ -96,24 +135,18 @@
protected boolean onStateChange(int[] stateSet) {
super.onStateChange(stateSet);
- // TODO: Implicitly tie states to ripple IDs. For now, just clear
- // focused and pressed if they aren't in the state set.
- boolean hasFocused = false;
- boolean hasPressed = false;
- for (int i = 0; i < stateSet.length; i++) {
- if (stateSet[i] == R.attr.state_pressed) {
- hasPressed = true;
- } else if (stateSet[i] == R.attr.state_focused) {
- hasFocused = true;
- }
- }
-
- if (!hasPressed) {
+ final boolean pressed = Arrays.contains(stateSet, R.attr.state_pressed);
+ if (!pressed) {
removeHotspot(R.attr.state_pressed);
+ } else {
+ activateHotspot(R.attr.state_pressed);
}
- if (!hasFocused) {
+ final boolean focused = Arrays.contains(stateSet, R.attr.state_focused);
+ if (!focused) {
removeHotspot(R.attr.state_focused);
+ } else {
+ activateHotspot(R.attr.state_focused);
}
if (mRipplePaint != null && mState.mTint != null) {
@@ -138,19 +171,7 @@
mHotspotBounds.set(bounds);
}
- onHotspotBoundsChange();
- }
-
- private void onHotspotBoundsChange() {
- final int x = mHotspotBounds.centerX();
- final int y = mHotspotBounds.centerY();
- final int N = mAnimatingRipplesCount;
- for (int i = 0; i < N; i++) {
- if (mState.mPinned) {
- mAnimatingRipples[i].move(x, y);
- }
- mAnimatingRipples[i].onBoundsChanged();
- }
+ invalidateSelf();
}
@Override
@@ -172,7 +193,7 @@
@Override
public boolean isStateful() {
- return super.isStateful() || mState.mTint != null && mState.mTint.isStateful();
+ return true;
}
/**
@@ -213,7 +234,7 @@
throws XmlPullParserException, IOException {
final TypedArray a = obtainAttributes(
r, theme, attrs, R.styleable.TouchFeedbackDrawable);
- inflateStateFromTypedArray(a);
+ updateStateFromTypedArray(a);
a.recycle();
super.inflate(r, parser, attrs, theme);
@@ -245,25 +266,23 @@
/**
* Initializes the constant state from the values in the typed array.
*/
- private void inflateStateFromTypedArray(TypedArray a) {
+ private void updateStateFromTypedArray(TypedArray a) {
final TouchFeedbackState state = mState;
// Extract the theme attributes, if any.
- final int[] themeAttrs = a.extractThemeAttrs();
- state.mTouchThemeAttrs = themeAttrs;
+ state.mTouchThemeAttrs = a.extractThemeAttrs();
- if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tint] == 0) {
- mState.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+ final ColorStateList tint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+ if (tint != null) {
+ mState.mTint = tint;
}
- if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
- mState.setTintMode(Drawable.parseTintMode(
- a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
+ final int tintMode = a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1);
+ if (tintMode != -1) {
+ mState.setTintMode(Drawable.parseTintMode(tintMode, Mode.SRC_ATOP));
}
- if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
- mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
- }
+ mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, mState.mPinned);
}
/**
@@ -283,38 +302,14 @@
super.applyTheme(t);
final TouchFeedbackState state = mState;
- if (state == null) {
- throw new RuntimeException(
- "Can't apply theme to <touch-feedback> with no constant state");
+ if (state == null || state.mTouchThemeAttrs == null) {
+ return;
}
- final int[] themeAttrs = state.mTouchThemeAttrs;
- if (themeAttrs != null) {
- final TypedArray a = t.resolveAttributes(
- themeAttrs, R.styleable.TouchFeedbackDrawable);
- updateStateFromTypedArray(a);
- a.recycle();
- }
- }
-
- /**
- * Updates the constant state from the values in the typed array.
- */
- private void updateStateFromTypedArray(TypedArray a) {
- final TouchFeedbackState state = mState;
-
- if (a.hasValue(R.styleable.TouchFeedbackDrawable_tint)) {
- state.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
- }
-
- if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
- mState.setTintMode(Drawable.parseTintMode(
- a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
- }
-
- if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
- mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
- }
+ final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
+ R.styleable.TouchFeedbackDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
}
@Override
@@ -329,59 +324,123 @@
@Override
public void setHotspot(int id, float x, float y) {
- if (mRipples == null) {
- mRipples = new SparseArray<Ripple>();
- mAnimatingRipples = new Ripple[MAX_RIPPLES];
+ if (mState.mPinned && !circleContains(mHotspotBounds, x, y)) {
+ x = mHotspotBounds.exactCenterX();
+ y = mHotspotBounds.exactCenterY();
}
- if (mAnimatingRipplesCount >= MAX_RIPPLES) {
- Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+ final int[] stateSet = getState();
+ if (!Arrays.contains(stateSet, id)) {
+ // The hotspot is not active, so just modify the pending location.
+ getOrCreatePendingHotspot(id).set(x, y);
return;
}
- final Ripple ripple = mRipples.get(id);
- if (ripple == null) {
- final Rect bounds = mHotspotBounds;
- if (mState.mPinned) {
- x = bounds.exactCenterX();
- y = bounds.exactCenterY();
- }
-
- // TODO: Clean this up in the API.
- final boolean pulse = (id != R.attr.state_focused);
- final Ripple newRipple = new Ripple(this, bounds, mDensity, pulse);
- newRipple.move(x, y);
-
- mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
- mRipples.put(id, newRipple);
- } else if (mState.mPinned) {
- final Rect bounds = mHotspotBounds;
- x = bounds.exactCenterX();
- y = bounds.exactCenterY();
- ripple.move(x, y);
- } else {
- ripple.move(x, y);
+ if (mAnimatingRipplesCount >= MAX_RIPPLES) {
+ // This should never happen unless the user is tapping like a maniac
+ // or there is a bug that's preventing ripples from being removed.
+ Log.d(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+ return;
}
+
+ if (mActiveHotspots == null) {
+ mActiveHotspots = new SparseArray<Ripple>();
+ mAnimatingRipples = new Ripple[MAX_RIPPLES];
+ }
+
+ final Ripple ripple = mActiveHotspots.get(id);
+ if (ripple != null) {
+ // The hotspot is active, but we can't move it because it's probably
+ // busy animating the center position.
+ return;
+ }
+
+ // The hotspot needs to be made active.
+ createActiveHotspot(id, x, y);
+ }
+
+ private boolean circleContains(Rect bounds, float x, float y) {
+ final float pX = bounds.exactCenterX() - x;
+ final float pY = bounds.exactCenterY() - y;
+ final double pointRadius = Math.sqrt(pX * pX + pY * pY);
+
+ final float bX = bounds.width() / 2.0f;
+ final float bY = bounds.height() / 2.0f;
+ final double boundsRadius = Math.sqrt(bX * bX + bY * bY);
+
+ return pointRadius < boundsRadius;
+ }
+
+ private PointF getOrCreatePendingHotspot(int id) {
+ final PointF p;
+ if (mPendingHotspots == null) {
+ mPendingHotspots = new SparseArray<>(2);
+ p = null;
+ } else {
+ p = mPendingHotspots.get(id);
+ }
+
+ if (p == null) {
+ final PointF newPoint = new PointF();
+ mPendingHotspots.put(id, newPoint);
+ return newPoint;
+ } else {
+ return p;
+ }
+ }
+
+ /**
+ * Moves a hotspot from pending to active.
+ */
+ private void activateHotspot(int id) {
+ final SparseArray<PointF> pendingHotspots = mPendingHotspots;
+ if (pendingHotspots != null) {
+ final int index = pendingHotspots.indexOfKey(id);
+ if (index >= 0) {
+ final PointF hotspot = pendingHotspots.valueAt(index);
+ pendingHotspots.removeAt(index);
+ createActiveHotspot(id, hotspot.x, hotspot.y);
+ }
+ }
+ }
+
+ /**
+ * Creates an active hotspot at the specified location.
+ */
+ private void createActiveHotspot(int id, float x, float y) {
+ final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+ final Ripple newRipple = new Ripple(this, mHotspotBounds, color);
+ newRipple.enter(x, y);
+
+ if (mAnimatingRipples == null) {
+ mAnimatingRipples = new Ripple[MAX_RIPPLES];
+ }
+ mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
+
+ if (mActiveHotspots == null) {
+ mActiveHotspots = new SparseArray<Ripple>();
+ }
+ mActiveHotspots.put(id, newRipple);
}
@Override
public void removeHotspot(int id) {
- if (mRipples == null) {
+ if (mActiveHotspots == null) {
return;
}
- final Ripple ripple = mRipples.get(id);
+ final Ripple ripple = mActiveHotspots.get(id);
if (ripple != null) {
ripple.exit();
- mRipples.remove(id);
+ mActiveHotspots.remove(id);
}
}
@Override
public void clearHotspots() {
- if (mRipples != null) {
- mRipples.clear();
+ if (mActiveHotspots != null) {
+ mActiveHotspots.clear();
}
final int count = mAnimatingRipplesCount;
@@ -402,7 +461,6 @@
public void setHotspotBounds(int left, int top, int right, int bottom) {
mOverrideBounds = true;
mHotspotBounds.set(left, top, right, bottom);
- onHotspotBoundsChange();
}
@Override
@@ -412,9 +470,9 @@
final ChildDrawable[] array = mLayerState.mChildren;
final boolean maskOnly = mState.mMask != null && N == 1;
- int restoreToCount = drawRippleLayer(canvas, bounds, maskOnly);
+ int restoreToCount = drawRippleLayer(canvas, maskOnly);
- if (restoreToCount >= 0) {
+ if (restoreToCount >= 0) {
// We have a ripple layer that contains ripples. If we also have an
// explicit mask drawable, apply it now using DST_IN blending.
if (mState.mMask != null) {
@@ -450,7 +508,7 @@
}
}
- private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
+ private int drawRippleLayer(Canvas canvas, boolean maskOnly) {
final int count = mAnimatingRipplesCount;
if (count == 0) {
return -1;
@@ -458,7 +516,7 @@
final Ripple[] ripples = mAnimatingRipples;
final boolean projected = isProjected();
- final Rect layerBounds = projected ? getDirtyBounds() : bounds;
+ final Rect layerBounds = projected ? getDirtyBounds() : getBounds();
// Separate the ripple color and alpha channel. The alpha will be
// applied when we merge the ripples down to the canvas.
@@ -479,6 +537,7 @@
boolean drewRipples = false;
int restoreToCount = -1;
+ int restoreTranslate = -1;
int animatingCount = 0;
// Draw ripples and update the animating ripples array.
@@ -509,6 +568,10 @@
restoreToCount = canvas.saveLayer(layerBounds.left, layerBounds.top,
layerBounds.right, layerBounds.bottom, layerPaint);
layerPaint.setAlpha(255);
+
+ restoreTranslate = canvas.save();
+ // Translate the canvas to the current hotspot bounds.
+ canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
}
drewRipples |= ripple.draw(canvas, ripplePaint);
@@ -519,6 +582,11 @@
mAnimatingRipplesCount = animatingCount;
+ // Always restore the translation.
+ if (restoreTranslate >= 0) {
+ canvas.restoreToCount(restoreTranslate);
+ }
+
// If we created a layer with no content, merge it immediately.
if (restoreToCount >= 0 && !drewRipples) {
canvas.restoreToCount(restoreToCount);
@@ -543,11 +611,14 @@
dirtyBounds.set(drawingBounds);
drawingBounds.setEmpty();
+ final int cX = (int) mHotspotBounds.exactCenterX();
+ final int cY = (int) mHotspotBounds.exactCenterY();
final Rect rippleBounds = mTempRect;
final Ripple[] activeRipples = mAnimatingRipples;
final int N = mAnimatingRipplesCount;
for (int i = 0; i < N; i++) {
activeRipples[i].getBounds(rippleBounds);
+ rippleBounds.offset(cX, cY);
drawingBounds.union(rippleBounds);
}
@@ -563,11 +634,11 @@
static class TouchFeedbackState extends LayerState {
int[] mTouchThemeAttrs;
- ColorStateList mTint;
- PorterDuffXfermode mTintXfermode;
- PorterDuffXfermode mTintXfermodeInverse;
+ ColorStateList mTint = null;
+ PorterDuffXfermode mTintXfermode = SRC_ATOP;
+ PorterDuffXfermode mTintXfermodeInverse = DST_ATOP;
Drawable mMask;
- boolean mPinned;
+ boolean mPinned = false;
public TouchFeedbackState(
TouchFeedbackState orig, TouchFeedbackDrawable owner, Resources res) {
diff --git a/include/android_runtime/android_hardware_camera2_CameraMetadata.h b/include/android_runtime/android_hardware_camera2_CameraMetadata.h
new file mode 100644
index 0000000..3c76ca5
--- /dev/null
+++ b/include/android_runtime/android_hardware_camera2_CameraMetadata.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA2_CAMERAMETADATA_JNI_H
+#define ANDROID_HARDWARE_CAMERA2_CAMERAMETADATA_JNI_H
+
+#include <camera/CameraMetadata.h>
+
+#include "jni.h"
+
+namespace android {
+
+/**
+ * Copies the native metadata for this java object into the given output CameraMetadata object.
+ */
+status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
+ /*out*/CameraMetadata* metadata);
+
+} /*namespace android*/
+
+#endif /*ANDROID_HARDWARE_CAMERA2_CAMERAMETADATA_JNI_H*/
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 83eedfb..b80f7e9 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -37,7 +37,10 @@
, mInterpolator(0)
, mPlayState(NEEDS_START)
, mStartTime(0)
- , mDuration(300){
+ , mDelayUntil(0)
+ , mDuration(300)
+ , mStartDelay(0) {
+
}
BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
@@ -49,10 +52,6 @@
mInterpolator = interpolator;
}
-void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
- mDuration = duration;
-}
-
void BaseRenderNodeAnimator::setStartValue(float value) {
LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
"Cannot set the start value after the animator has started!");
@@ -68,7 +67,24 @@
}
}
+void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
+ mDuration = duration;
+}
+
+void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
+ mStartDelay = startDelay;
+}
+
bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
+ if (mPlayState == PENDING && mStartDelay > 0 && mDelayUntil == 0) {
+ mDelayUntil = info.frameTimeMs + mStartDelay;
+ return false;
+ }
+
+ if (mDelayUntil > info.frameTimeMs) {
+ return false;
+ }
+
if (mPlayState == PENDING) {
mPlayState = RUNNING;
mStartTime = info.frameTimeMs;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fe88cbf..7741617 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -44,6 +44,8 @@
ANDROID_API void setInterpolator(Interpolator* interpolator);
ANDROID_API void setDuration(nsecs_t durationInMs);
ANDROID_API nsecs_t duration() { return mDuration; }
+ ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
+ ANDROID_API nsecs_t startDelay() { return mStartDelay; }
ANDROID_API void setListener(AnimationListener* listener) {
mListener = listener;
}
@@ -82,10 +84,12 @@
Interpolator* mInterpolator;
PlayState mPlayState;
- long mStartTime;
- long mDuration;
+ nsecs_t mStartTime;
+ nsecs_t mDelayUntil;
+ nsecs_t mDuration;
+ nsecs_t mStartDelay;
- sp<AnimationListener> mListener;
+ sp<AnimationListener> mListener;
};
class RenderPropertyAnimator : public BaseRenderNodeAnimator {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 435736c..485dbf6 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -136,7 +136,7 @@
* Returns the current clip in local coordinates. The clip rect is
* transformed by the inverse transform matrix.
*/
- const Rect& getLocalClip();
+ ANDROID_API const Rect& getLocalClip();
/**
* Returns the current clip in render target coordinates.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1dcfcb8..3a3f76d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -428,7 +428,6 @@
public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
private static IAudioService sService;
- private MediaSessionLegacyHelper mSessionHelper;
/**
* @hide
@@ -439,9 +438,6 @@
com.android.internal.R.bool.config_useMasterVolume);
mUseVolumeKeySounds = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useVolumeKeySounds);
- if (USE_SESSIONS) {
- mSessionHelper = MediaSessionLegacyHelper.getHelper(context);
- }
}
private static IAudioService getService()
@@ -478,11 +474,16 @@
* or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
*/
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
- IAudioService service = getService();
- try {
- service.dispatchMediaKeyEvent(keyEvent);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+ if (USE_SESSIONS) {
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.sendMediaButtonEvent(keyEvent, false);
+ } else {
+ IAudioService service = getService();
+ try {
+ service.dispatchMediaKeyEvent(keyEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+ }
}
}
@@ -2178,7 +2179,8 @@
Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
}
if (USE_SESSIONS) {
- mSessionHelper.addMediaButtonListener(pi, mContext);
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.addMediaButtonListener(pi, mContext);
}
}
@@ -2254,7 +2256,8 @@
Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
}
if (USE_SESSIONS) {
- mSessionHelper.removeMediaButtonListener(pi);
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.removeMediaButtonListener(pi);
}
}
@@ -2281,7 +2284,7 @@
Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
}
if (USE_SESSIONS) {
- rcClient.registerWithSession(mSessionHelper);
+ rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
}
}
@@ -2303,7 +2306,7 @@
Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
}
if (USE_SESSIONS) {
- rcClient.unregisterWithSession(mSessionHelper);
+ rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
}
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 384e120..d4e85c8 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -61,25 +61,25 @@
*/
public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
- // Error codes:
- // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
/**
* Denotes a successful operation.
*/
- public static final int SUCCESS = 0;
+ public static final int SUCCESS = AudioSystem.SUCCESS;
/**
* Denotes a generic operation failure.
*/
- public static final int ERROR = -1;
+ public static final int ERROR = AudioSystem.ERROR;
/**
* Denotes a failure due to the use of an invalid value.
*/
- public static final int ERROR_BAD_VALUE = -2;
+ public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
/**
* Denotes a failure due to the improper use of a method.
*/
- public static final int ERROR_INVALID_OPERATION = -3;
+ public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
+ // Error codes:
+ // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16;
private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK = -17;
private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 724022b..bb8cfa6 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -46,6 +46,7 @@
import android.hardware.usb.UsbManager;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
+import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
@@ -108,6 +109,10 @@
/** Debug volumes */
protected static final boolean DEBUG_VOL = false;
+ /** Reroute calls to media session apis */
+ private static final boolean USE_SESSIONS = true;
+ private static final boolean DEBUG_SESSIONS = true;
+
/** How long to delay before persisting a change in volume/ringer mode. */
private static final int PERSIST_DELAY = 500;
@@ -3472,7 +3477,7 @@
if (volume < 0) {
volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
} else {
- volFloat = (float) volume / 1000.0f;
+ volFloat = volume / 1000.0f;
}
if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
@@ -3554,7 +3559,7 @@
}
Settings.System.putFloatForUser(mContentResolver,
Settings.System.VOLUME_MASTER,
- (float)msg.arg1 / (float)1000.0,
+ msg.arg1 / (float)1000.0,
UserHandle.USER_CURRENT);
break;
@@ -4325,11 +4330,27 @@
}
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
- mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+ if (USE_SESSIONS) {
+ if (DEBUG_SESSIONS) {
+ int pid = getCallingPid();
+ Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
+ }
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
+ } else {
+ mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+ }
}
public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
- mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+ if (USE_SESSIONS) {
+ if (DEBUG_SESSIONS) {
+ int pid = getCallingPid();
+ Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
+ }
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
+ } else {
+ mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+ }
}
//==========================================================================================
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 327c10c..5ddb198 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -199,6 +199,17 @@
}
}
+ /*
+ * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
+ * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h
+ */
+ public static final int SUCCESS = 0;
+ public static final int ERROR = -1;
+ public static final int BAD_VALUE = -2;
+ public static final int INVALID_OPERATION = -3;
+ public static final int PERMISSION_DENIED = -4;
+ public static final int NO_INIT = -5;
+ public static final int DEAD_OBJECT = -6;
/*
* AudioPolicyService methods
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1a64cff..1baaaa4 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -125,25 +125,25 @@
*/
public static final int STATE_NO_STATIC_DATA = 2;
- // Error codes:
- // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
/**
* Denotes a successful operation.
*/
- public static final int SUCCESS = 0;
+ public static final int SUCCESS = AudioSystem.SUCCESS;
/**
* Denotes a generic operation failure.
*/
- public static final int ERROR = -1;
+ public static final int ERROR = AudioSystem.ERROR;
/**
* Denotes a failure due to the use of an invalid value.
*/
- public static final int ERROR_BAD_VALUE = -2;
+ public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
/**
* Denotes a failure due to the improper use of a method.
*/
- public static final int ERROR_INVALID_OPERATION = -3;
+ public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
+ // Error codes:
+ // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -16;
private static final int ERROR_NATIVESETUP_INVALIDCHANNELMASK = -17;
private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -18;
diff --git a/media/java/android/media/DngCreator.java b/media/java/android/media/DngCreator.java
index b2a38ab..76c6d46 100644
--- a/media/java/android/media/DngCreator.java
+++ b/media/java/android/media/DngCreator.java
@@ -17,9 +17,12 @@
package android.media;
import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.impl.CameraMetadataNative;
import android.location.Location;
+import android.util.Size;
import java.io.IOException;
import java.io.InputStream;
@@ -50,7 +53,7 @@
* Adobe DNG 1.4.0.0 specification</a>.
* </p>
*/
-public final class DngCreator {
+public final class DngCreator implements AutoCloseable {
/**
* Create a new DNG object.
@@ -68,7 +71,12 @@
* {@link android.hardware.camera2.CameraCharacteristics}.
* @param metadata a metadata object to generate tags from.
*/
- public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {/*TODO*/}
+ public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {
+ if (characteristics == null || metadata == null) {
+ throw new NullPointerException("Null argument to DngCreator constructor");
+ }
+ nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy());
+ }
/**
* Set the orientation value to write.
@@ -92,6 +100,13 @@
* @return this {@link #DngCreator} object.
*/
public DngCreator setOrientation(int orientation) {
+
+ if (orientation < ExifInterface.ORIENTATION_UNDEFINED ||
+ orientation > ExifInterface.ORIENTATION_ROTATE_270) {
+ throw new IllegalArgumentException("Orientation " + orientation +
+ " is not a valid EXIF orientation value");
+ }
+ nativeSetOrientation(orientation);
return this;
}
@@ -111,6 +126,20 @@
* @return this {@link #DngCreator} object.
*/
public DngCreator setThumbnail(Bitmap pixels) {
+ if (pixels == null) {
+ throw new NullPointerException("Null argument to setThumbnail");
+ }
+
+ Bitmap.Config config = pixels.getConfig();
+
+ if (config != Bitmap.Config.ARGB_8888) {
+ pixels = pixels.copy(Bitmap.Config.ARGB_8888, false);
+ if (pixels == null) {
+ throw new IllegalArgumentException("Unsupported Bitmap format " + config);
+ }
+ nativeSetThumbnailBitmap(pixels);
+ }
+
return this;
}
@@ -130,6 +159,21 @@
* @return this {@link #DngCreator} object.
*/
public DngCreator setThumbnail(Image pixels) {
+ if (pixels == null) {
+ throw new NullPointerException("Null argument to setThumbnail");
+ }
+
+ int format = pixels.getFormat();
+ if (format != ImageFormat.YUV_420_888) {
+ throw new IllegalArgumentException("Unsupported image format " + format);
+ }
+
+ Image.Plane[] planes = pixels.getPlanes();
+ nativeSetThumbnailImage(pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
+ planes[0].getRowStride(), planes[0].getPixelStride(), planes[1].getBuffer(),
+ planes[1].getRowStride(), planes[1].getPixelStride(), planes[1].getBuffer(),
+ planes[1].getRowStride(), planes[1].getPixelStride());
+
return this;
}
@@ -150,7 +194,10 @@
* @throws java.lang.IllegalArgumentException if the given location object doesn't
* contain enough information to set location metadata.
*/
- public DngCreator setLocation(Location location) { return this; }
+ public DngCreator setLocation(Location location) {
+ /*TODO*/
+ return this;
+ }
/**
* Set the user description string to write.
@@ -163,6 +210,7 @@
* @return this {@link #DngCreator} object.
*/
public DngCreator setDescription(String description) {
+ /*TODO*/
return this;
}
@@ -172,32 +220,33 @@
*
* <p>
* Raw pixel data must have 16 bits per pixel, and the input must contain at least
- * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes. The width and height of
+ * {@code offset + 2 * width * height)} bytes. The width and height of
* the input are taken from the width and height set in the {@link DngCreator} metadata tags,
* and will typically be equal to the width and height of
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
- * If insufficient metadata is set to write a well-formatted DNG file, and
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
+ * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}. If insufficient
+ * metadata is available to write a well-formatted DNG file, an
* {@link java.lang.IllegalStateException} will be thrown.
* </p>
*
- * <p>
- * When reading from the pixel input, {@code stride} pixels will be skipped
- * after each row (excluding the last).
- * </p>
- *
* @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+ * @param size the {@link Size} of the image to write, in pixels.
* @param pixels an {@link java.io.InputStream} of pixel data to write.
- * @param stride the stride of the raw image in pixels.
* @param offset the offset of the raw image in bytes. This indicates how many bytes will
* be skipped in the input before any pixel data is read.
*
* @throws IOException if an error was encountered in the input or output stream.
* @throws java.lang.IllegalStateException if not enough metadata information has been
* set to write a well-formatted DNG file.
+ * @throws java.lang.IllegalArgumentException if the size passed in does not match the
*/
- public void writeInputStream(OutputStream dngOutput, InputStream pixels, int stride,
- long offset) throws IOException {
- /*TODO*/
+ public void writeInputStream(OutputStream dngOutput, Size size, InputStream pixels, long offset)
+ throws IOException {
+ if (dngOutput == null || pixels == null) {
+ throw new NullPointerException("Null argument to writeImage");
+ }
+ nativeWriteInputStream(dngOutput, pixels, offset);
}
/**
@@ -206,22 +255,18 @@
*
* <p>
* Raw pixel data must have 16 bits per pixel, and the input must contain at least
- * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes. The width and height of
+ * {@code offset + 2 * width * height)} bytes. The width and height of
* the input are taken from the width and height set in the {@link DngCreator} metadata tags,
* and will typically be equal to the width and height of
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
- * If insufficient metadata is set to write a well-formatted DNG file, and
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
+ * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}. If insufficient
+ * metadata is available to write a well-formatted DNG file, an
* {@link java.lang.IllegalStateException} will be thrown.
* </p>
*
- * <p>
- * When reading from the pixel input, {@code stride} pixels will be skipped
- * after each row (excluding the last).
- * </p>
- *
* @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
* @param pixels an {@link java.nio.ByteBuffer} of pixel data to write.
- * @param stride the stride of the raw image in pixels.
* @param offset the offset of the raw image in bytes. This indicates how many bytes will
* be skipped in the input before any pixel data is read.
*
@@ -229,8 +274,13 @@
* @throws java.lang.IllegalStateException if not enough metadata information has been
* set to write a well-formatted DNG file.
*/
- public void writeByteBuffer(OutputStream dngOutput, ByteBuffer pixels, int stride,
- long offset) throws IOException {/*TODO*/}
+ public void writeByteBuffer(OutputStream dngOutput, Size size, ByteBuffer pixels, long offset)
+ throws IOException {
+ if (dngOutput == null || pixels == null) {
+ throw new NullPointerException("Null argument to writeImage");
+ }
+ nativeWriteByteBuffer(dngOutput, pixels, offset);
+ }
/**
* Write the pixel data to a DNG file with the currently configured metadata.
@@ -249,6 +299,70 @@
* @throws java.lang.IllegalStateException if not enough metadata information has been
* set to write a well-formatted DNG file.
*/
- public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {/*TODO*/}
+ public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {
+ if (dngOutput == null || pixels == null) {
+ throw new NullPointerException("Null argument to writeImage");
+ }
+ int format = pixels.getFormat();
+ if (format != ImageFormat.RAW_SENSOR) {
+ throw new IllegalArgumentException("Unsupported image format " + format);
+ }
+
+ Image.Plane[] planes = pixels.getPlanes();
+ nativeWriteImage(dngOutput, pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
+ planes[0].getRowStride(), planes[0].getPixelStride());
+ }
+
+ @Override
+ public void close() {
+ nativeDestroy();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * This field is used by native code, do not access or modify.
+ */
+ private long mNativeContext;
+
+ private static native void nativeClassInit();
+
+ private synchronized native void nativeInit(CameraMetadataNative nativeCharacteristics,
+ CameraMetadataNative nativeResult);
+
+ private synchronized native void nativeDestroy();
+
+ private synchronized native void nativeSetOrientation(int orientation);
+
+ private synchronized native void nativeSetThumbnailBitmap(Bitmap bitmap);
+
+ private synchronized native void nativeSetThumbnailImage(int width, int height,
+ ByteBuffer yBuffer, int yRowStride,
+ int yPixStride, ByteBuffer uBuffer,
+ int uRowStride, int uPixStride,
+ ByteBuffer vBuffer, int vRowStride,
+ int vPixStride);
+
+ private synchronized native void nativeWriteImage(OutputStream out, int width, int height,
+ ByteBuffer rawBuffer, int rowStride,
+ int pixStride) throws IOException;
+
+ private synchronized native void nativeWriteByteBuffer(OutputStream out, ByteBuffer rawBuffer,
+ long offset) throws IOException;
+
+ private synchronized native void nativeWriteInputStream(OutputStream out, InputStream rawStream,
+ long offset) throws IOException;
+
+ static {
+ System.loadLibrary("media_jni");
+ nativeClassInit();
+ }
}
diff --git a/media/java/android/media/session/MediaMetadata.aidl b/media/java/android/media/MediaMetadata.aidl
similarity index 95%
rename from media/java/android/media/session/MediaMetadata.aidl
rename to media/java/android/media/MediaMetadata.aidl
index 4431d9d..66ee483 100644
--- a/media/java/android/media/session/MediaMetadata.aidl
+++ b/media/java/android/media/MediaMetadata.aidl
@@ -13,6 +13,6 @@
** limitations under the License.
*/
-package android.media.session;
+package android.media;
parcelable MediaMetadata;
diff --git a/media/java/android/media/session/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
similarity index 98%
rename from media/java/android/media/session/MediaMetadata.java
rename to media/java/android/media/MediaMetadata.java
index 8a8af45..ff73a10 100644
--- a/media/java/android/media/session/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -13,12 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.media.session;
+package android.media;
import android.graphics.Bitmap;
-import android.media.MediaMetadataEditor;
-import android.media.MediaMetadataRetriever;
-import android.media.Rating;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
index 1a4e8da..ca44e9d 100644
--- a/media/java/android/media/MediaMetadataEditor.java
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -17,7 +17,6 @@
package android.media;
import android.graphics.Bitmap;
-import android.media.session.MediaMetadata;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 8368df94..37f45c2 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -24,10 +24,9 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
-import android.media.session.MediaMetadata;
import android.media.session.MediaSessionLegacyHelper;
import android.media.session.PlaybackState;
-import android.media.session.Session;
+import android.media.session.MediaSession;
import android.media.session.TransportPerformer;
import android.os.Bundle;
import android.os.Handler;
@@ -341,7 +340,7 @@
*/
public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
- private Session mSession;
+ private MediaSession mSession;
/**
* Class constructor.
diff --git a/media/java/android/media/routeprovider/RouteConnection.java b/media/java/android/media/routeprovider/RouteConnection.java
index 9214ff8..43692c1 100644
--- a/media/java/android/media/routeprovider/RouteConnection.java
+++ b/media/java/android/media/routeprovider/RouteConnection.java
@@ -40,6 +40,7 @@
* interfaces. Use {@link #addRouteInterface(String)} to add an interface and
* {@link #getRouteInterface(String)} to retrieve the interface's handle anytime
* after it has been added.
+ * @hide
*/
public final class RouteConnection {
private static final String TAG = "RouteConnection";
diff --git a/media/java/android/media/routeprovider/RouteInterfaceHandler.java b/media/java/android/media/routeprovider/RouteInterfaceHandler.java
index 9693dc6..e7f8bbf 100644
--- a/media/java/android/media/routeprovider/RouteInterfaceHandler.java
+++ b/media/java/android/media/routeprovider/RouteInterfaceHandler.java
@@ -16,7 +16,7 @@
package android.media.routeprovider;
import android.media.session.Route;
-import android.media.session.Session;
+import android.media.session.MediaSession;
import android.media.session.RouteInterface;
import android.os.Bundle;
import android.os.Handler;
@@ -33,7 +33,7 @@
* connected media route.
* <p>
* A {@link RouteProviderService} may expose multiple interfaces on a
- * {@link RouteConnection} for a {@link Session} to interact with. A
+ * {@link RouteConnection} for a {@link MediaSession} to interact with. A
* provider creates an interface with
* {@link RouteConnection#addRouteInterface(String)} to allow messages to be
* routed appropriately. Events are then sent through a specific interface and
@@ -47,6 +47,7 @@
* It is recommended you wrap this interface with a standard implementation to
* avoid errors, but for simple interfaces this class may be used directly. TODO
* add link to sample code.
+ * @hide
*/
public final class RouteInterfaceHandler {
private static final String TAG = "RouteInterfaceHandler";
@@ -184,7 +185,7 @@
public abstract static class CommandListener {
/**
* This is called when a command is received that matches this
- * interface. Commands are sent by a {@link Session} that is
+ * interface. Commands are sent by a {@link MediaSession} that is
* connected to the route this interface is registered with.
*
* @param iface The interface the command was received on.
@@ -197,7 +198,7 @@
* true may be returned if the command will be handled
* asynchronously.
* @see Route
- * @see Session
+ * @see MediaSession
*/
public abstract boolean onCommand(RouteInterfaceHandler iface, String command, Bundle args,
ResultReceiver cb);
diff --git a/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java b/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
index dcef79a..f2c40d2 100644
--- a/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
+++ b/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
@@ -28,6 +28,7 @@
* Standard wrapper for using playback controls over a {@link RouteInterfaceHandler}.
* This is the provider half of the interface. Sessions should use
* {@link RoutePlaybackControls} to interact with this interface.
+ * @hide
*/
public final class RoutePlaybackControlsHandler {
private static final String TAG = "RoutePlaybackControls";
diff --git a/media/java/android/media/routeprovider/RouteProviderService.java b/media/java/android/media/routeprovider/RouteProviderService.java
index 6ebfb5b..a6ef0bb 100644
--- a/media/java/android/media/routeprovider/RouteProviderService.java
+++ b/media/java/android/media/routeprovider/RouteProviderService.java
@@ -64,6 +64,7 @@
* </intent-filter>
* </service>
* </pre>
+ * @hide
*/
public abstract class RouteProviderService extends Service {
private static final String TAG = "RouteProvider";
diff --git a/media/java/android/media/routeprovider/RouteRequest.java b/media/java/android/media/routeprovider/RouteRequest.java
index 68475c0..2ba75de 100644
--- a/media/java/android/media/routeprovider/RouteRequest.java
+++ b/media/java/android/media/routeprovider/RouteRequest.java
@@ -16,7 +16,7 @@
package android.media.routeprovider;
import android.media.session.RouteOptions;
-import android.media.session.SessionInfo;
+import android.media.session.MediaSessionInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,16 +30,17 @@
* provides the full set of connection parameters they would like to use for a
* connection. An app that can connect in multiple ways will be represented by
* multiple requests.
+ * @hide
*/
public final class RouteRequest implements Parcelable {
- private final SessionInfo mSessionInfo;
+ private final MediaSessionInfo mSessionInfo;
private final RouteOptions mOptions;
private final boolean mActive;
/**
* @hide
*/
- public RouteRequest(SessionInfo info, RouteOptions connRequest,
+ public RouteRequest(MediaSessionInfo info, RouteOptions connRequest,
boolean active) {
mSessionInfo = info;
mOptions = connRequest;
@@ -47,7 +48,7 @@
}
private RouteRequest(Parcel in) {
- mSessionInfo = SessionInfo.CREATOR.createFromParcel(in);
+ mSessionInfo = MediaSessionInfo.CREATOR.createFromParcel(in);
mOptions = RouteOptions.CREATOR.createFromParcel(in);
mActive = in.readInt() != 0;
}
@@ -57,7 +58,7 @@
*
* @return Info on the session making the request
*/
- public SessionInfo getSessionInfo() {
+ public MediaSessionInfo getSessionInfo() {
return mSessionInfo;
}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 096550f..c4233c3 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -15,8 +15,8 @@
package android.media.session;
+import android.media.MediaMetadata;
import android.media.session.ISessionController;
-import android.media.session.MediaMetadata;
import android.media.session.RouteOptions;
import android.media.session.RouteCommand;
import android.media.session.RouteInfo;
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 1552513..7b0412e 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -28,7 +28,7 @@
*/
oneway interface ISessionCallback {
void onCommand(String command, in Bundle extras, in ResultReceiver cb);
- void onMediaButton(in Intent mediaButtonIntent);
+ void onMediaButton(in Intent mediaButtonIntent, in ResultReceiver cb);
void onRequestRouteChange(in RouteInfo route);
void onRouteConnected(in RouteInfo route, in RouteOptions options);
void onRouteDisconnected(in RouteInfo route, int reason);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e2e046f..5ddb6db 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -16,9 +16,9 @@
package android.media.session;
import android.content.Intent;
+import android.media.MediaMetadata;
import android.media.Rating;
import android.media.session.ISessionControllerCallback;
-import android.media.session.MediaMetadata;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.ResultReceiver;
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index bc1ae05..e823153 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -15,7 +15,7 @@
package android.media.session;
-import android.media.session.MediaMetadata;
+import android.media.MediaMetadata;
import android.media.session.RouteInfo;
import android.media.session.PlaybackState;
import android.os.Bundle;
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index e341647..38b92932 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -19,6 +19,7 @@
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
+import android.view.KeyEvent;
/**
* Interface to the MediaSessionManagerService
@@ -27,4 +28,5 @@
interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
List<IBinder> getSessions(in ComponentName compName, int userId);
+ void dispatchMediaKeyEvent(in KeyEvent keyEvent, boolean needWakeLock);
}
\ No newline at end of file
diff --git a/media/java/android/media/session/SessionController.java b/media/java/android/media/session/MediaController.java
similarity index 90%
rename from media/java/android/media/session/SessionController.java
rename to media/java/android/media/session/MediaController.java
index dc4f7d9..642ac2f 100644
--- a/media/java/android/media/session/SessionController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -16,6 +16,7 @@
package android.media.session;
+import android.media.MediaMetadata;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -34,13 +35,13 @@
* other commands can be sent to the session. A callback may be registered to
* receive updates from the session, such as metadata and play state changes.
* <p>
- * A MediaController can be created through {@link SessionManager} if you
+ * A MediaController can be created through {@link MediaSessionManager} if you
* hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if
- * you have a {@link SessionToken} from the session owner.
+ * you have a {@link MediaSessionToken} from the session owner.
* <p>
* MediaController objects are thread-safe.
*/
-public final class SessionController {
+public final class MediaController {
private static final String TAG = "SessionController";
private static final int MSG_EVENT = 1;
@@ -58,15 +59,15 @@
private TransportController mTransportController;
- private SessionController(ISessionController sessionBinder) {
+ private MediaController(ISessionController sessionBinder) {
mSessionBinder = sessionBinder;
}
/**
* @hide
*/
- public static SessionController fromBinder(ISessionController sessionBinder) {
- SessionController controller = new SessionController(sessionBinder);
+ public static MediaController fromBinder(ISessionController sessionBinder) {
+ MediaController controller = new MediaController(sessionBinder);
try {
controller.mSessionBinder.registerCallbackListener(controller.mCbStub);
if (controller.mSessionBinder.isTransportControlEnabled()) {
@@ -87,7 +88,7 @@
* @param token The session token to use
* @return A controller for the session or null
*/
- public static SessionController fromToken(SessionToken token) {
+ public static MediaController fromToken(MediaSessionToken token) {
return fromBinder(token.getBinder());
}
@@ -184,6 +185,8 @@
/**
* Request that the route picker be shown for this session. This should
* generally be called in response to a user action.
+ *
+ * @hide
*/
public void showRoutePicker() {
try {
@@ -285,22 +288,23 @@
/**
* Override to handle route changes for this session.
*
- * @param route
+ * @param route The new route
+ * @hide
*/
public void onRouteChanged(RouteInfo route) {
}
}
private final static class CallbackStub extends ISessionControllerCallback.Stub {
- private final WeakReference<SessionController> mController;
+ private final WeakReference<MediaController> mController;
- public CallbackStub(SessionController controller) {
- mController = new WeakReference<SessionController>(controller);
+ public CallbackStub(MediaController controller) {
+ mController = new WeakReference<MediaController>(controller);
}
@Override
public void onEvent(String event, Bundle extras) {
- SessionController controller = mController.get();
+ MediaController controller = mController.get();
if (controller != null) {
controller.postEvent(event, extras);
}
@@ -308,7 +312,7 @@
@Override
public void onRouteChanged(RouteInfo route) {
- SessionController controller = mController.get();
+ MediaController controller = mController.get();
if (controller != null) {
controller.postRouteChanged(route);
}
@@ -316,7 +320,7 @@
@Override
public void onPlaybackStateChanged(PlaybackState state) {
- SessionController controller = mController.get();
+ MediaController controller = mController.get();
if (controller != null) {
TransportController tc = controller.getTransportController();
if (tc != null) {
@@ -327,7 +331,7 @@
@Override
public void onMetadataChanged(MediaMetadata metadata) {
- SessionController controller = mController.get();
+ MediaController controller = mController.get();
if (controller != null) {
TransportController tc = controller.getTransportController();
if (tc != null) {
@@ -339,9 +343,9 @@
}
private final static class MessageHandler extends Handler {
- private final SessionController.Callback mCallback;
+ private final MediaController.Callback mCallback;
- public MessageHandler(Looper looper, SessionController.Callback cb) {
+ public MessageHandler(Looper looper, MediaController.Callback cb) {
super(looper, null, true);
mCallback = cb;
}
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/MediaSession.java
similarity index 89%
rename from media/java/android/media/session/Session.java
rename to media/java/android/media/session/MediaSession.java
index 2ffced6..5b9adaa 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -36,21 +36,21 @@
import java.util.List;
/**
- * Allows interaction with media controllers, media routes, volume keys, media
- * buttons, and transport controls.
+ * Allows interaction with media controllers, volume keys, media buttons, and
+ * transport controls.
* <p>
* A MediaSession should be created when an app wants to publish media playback
- * information or negotiate with a media route. In general an app only needs one
- * session for all playback, though multiple sessions can be created for sending
- * media to multiple routes or to provide finer grain controls of media.
+ * information or handle media keys. In general an app only needs one session
+ * for all playback, though multiple sessions can be created to provide finer
+ * grain controls of media.
* <p>
* A MediaSession is created by calling
- * {@link SessionManager#createSession(String)}. Once a session is created apps
- * that have the MEDIA_CONTENT_CONTROL permission can interact with the session
- * through
- * {@link SessionManager#getActiveSessions(android.content.ComponentName)}. The
- * owner of the session may also use {@link #getSessionToken()} to allow apps
- * without this permission to create a {@link SessionController} to interact
+ * {@link MediaSessionManager#createSession(String)}. Once a session is created
+ * apps that have the MEDIA_CONTENT_CONTROL permission can interact with the
+ * session through
+ * {@link MediaSessionManager#getActiveSessions(android.content.ComponentName)}.
+ * The owner of the session may also use {@link #getSessionToken()} to allow
+ * apps without this permission to create a {@link MediaController} to interact
* with this session.
* <p>
* To receive commands, media keys, and other events a Callback must be set with
@@ -61,7 +61,7 @@
* <p>
* MediaSession objects are thread safe
*/
-public final class Session {
+public final class MediaSession {
private static final String TAG = "Session";
/**
@@ -89,31 +89,43 @@
/**
* Indicates the session was disconnected because the user that the session
* belonged to is stopping.
+ * @hide
*/
public static final int DISCONNECT_REASON_USER_STOPPING = 1;
/**
* Indicates the session was disconnected because the provider disconnected
* the route.
+ * @hide
*/
public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2;
/**
* Indicates the session was disconnected because the route has changed.
+ * @hide
*/
public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3;
/**
* Indicates the session was disconnected because the session owner
* requested it disconnect.
+ * @hide
*/
public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4;
/**
* Indicates the session was disconnected because it was destroyed.
+ * @hide
*/
public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5;
+ /**
+ * Status code indicating the call was handled.
+ *
+ * @hide
+ */
+ public static final int RESULT_SUCCESS = 0;
+
private static final int MSG_MEDIA_BUTTON = 1;
private static final int MSG_COMMAND = 2;
private static final int MSG_ROUTE_CHANGE = 3;
@@ -126,7 +138,7 @@
private final Object mLock = new Object();
- private final SessionToken mSessionToken;
+ private final MediaSessionToken mSessionToken;
private final ISession mBinder;
private final CallbackStub mCbStub;
@@ -143,7 +155,7 @@
/**
* @hide
*/
- public Session(ISession binder, CallbackStub cbStub) {
+ public MediaSession(ISession binder, CallbackStub cbStub) {
mBinder = binder;
mCbStub = cbStub;
ISessionController controllerBinder = null;
@@ -152,7 +164,7 @@
} catch (RemoteException e) {
throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
}
- mSessionToken = new SessionToken(controllerBinder);
+ mSessionToken = new MediaSessionToken(controllerBinder);
mPerformer = new TransportPerformer(mBinder);
}
@@ -167,7 +179,7 @@
/**
* Add a callback to receive updates for the MediaSession. This includes
- * events like route updates, media buttons, and focus changes.
+ * media button and volume events.
*
* @param callback The callback to receive updates on.
* @param handler The handler that events should be posted on.
@@ -288,13 +300,13 @@
/**
* Retrieve a token object that can be used by apps to create a
- * {@link SessionController} for interacting with this session. The owner of
+ * {@link MediaController} for interacting with this session. The owner of
* the session is responsible for deciding how to distribute these tokens.
*
* @return A token that can be used to create a MediaController for this
* session
*/
- public SessionToken getSessionToken() {
+ public MediaSessionToken getSessionToken() {
return mSessionToken;
}
@@ -304,8 +316,8 @@
* Connection updates will be sent to the callback's
* {@link Callback#onRouteConnected(Route)} and
* {@link Callback#onRouteDisconnected(Route, int)} methods. If the
- * connection fails {@link Callback#onRouteDisconnected(Route, int)}
- * will be called.
+ * connection fails {@link Callback#onRouteDisconnected(Route, int)} will be
+ * called.
* <p>
* If you already have a connection to this route it will be disconnected
* before the new connection is established. TODO add an easy way to compare
@@ -313,6 +325,7 @@
*
* @param route The route the app is trying to connect to.
* @param request The connection request to use.
+ * @hide
*/
public void connect(RouteInfo route, RouteOptions request) {
if (route == null) {
@@ -331,6 +344,8 @@
/**
* Disconnect from the current route. After calling you will be switched
* back to the default route.
+ *
+ * @hide
*/
public void disconnect() {
if (mRoute != null) {
@@ -347,6 +362,7 @@
* will be used for picking valid routes.
*
* @param options The set of route options your app may use to connect.
+ * @hide
*/
public void setRouteOptions(List<RouteOptions> options) {
try {
@@ -491,6 +507,7 @@
* ongoing playback if necessary.
*
* @param route
+ * @hide
*/
public void onRequestRouteChange(RouteInfo route) {
}
@@ -500,6 +517,7 @@
* are now valid.
*
* @param route The route that was connected
+ * @hide
*/
public void onRouteConnected(Route route) {
}
@@ -519,6 +537,7 @@
*
* @param route The route that disconnected
* @param reason The reason for the disconnect
+ * @hide
*/
public void onRouteDisconnected(Route route, int reason) {
}
@@ -528,32 +547,36 @@
* @hide
*/
public static class CallbackStub extends ISessionCallback.Stub {
- private WeakReference<Session> mMediaSession;
+ private WeakReference<MediaSession> mMediaSession;
- public void setMediaSession(Session session) {
- mMediaSession = new WeakReference<Session>(session);
+ public void setMediaSession(MediaSession session) {
+ mMediaSession = new WeakReference<MediaSession>(session);
}
@Override
public void onCommand(String command, Bundle extras, ResultReceiver cb)
throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
session.postCommand(command, extras, cb);
}
}
@Override
- public void onMediaButton(Intent mediaButtonIntent) throws RemoteException {
- Session session = mMediaSession.get();
+ public void onMediaButton(Intent mediaButtonIntent, ResultReceiver cb)
+ throws RemoteException {
+ MediaSession session = mMediaSession.get();
if (session != null) {
session.postMediaButton(mediaButtonIntent);
}
+ if (cb != null) {
+ cb.send(RESULT_SUCCESS, null);
+ }
}
@Override
public void onRequestRouteChange(RouteInfo route) throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
session.postRequestRouteChange(route);
}
@@ -561,7 +584,7 @@
@Override
public void onRouteConnected(RouteInfo route, RouteOptions options) {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
session.postRouteConnected(route, options);
}
@@ -569,7 +592,7 @@
@Override
public void onRouteDisconnected(RouteInfo route, int reason) {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
session.postRouteDisconnected(route, reason);
}
@@ -577,7 +600,7 @@
@Override
public void onPlay() throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -588,7 +611,7 @@
@Override
public void onPause() throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -599,7 +622,7 @@
@Override
public void onStop() throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -610,7 +633,7 @@
@Override
public void onNext() throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -621,7 +644,7 @@
@Override
public void onPrevious() throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -632,7 +655,7 @@
@Override
public void onFastForward() throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -643,7 +666,7 @@
@Override
public void onRewind() throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -654,7 +677,7 @@
@Override
public void onSeekTo(long pos) throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -665,7 +688,7 @@
@Override
public void onRate(Rating rating) throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -676,7 +699,7 @@
@Override
public void onRouteEvent(RouteEvent event) throws RemoteException {
- Session session = mMediaSession.get();
+ MediaSession session = mMediaSession.get();
if (session != null) {
RouteInterface.EventListener iface
= session.mInterfaceListeners.get(event.getIface());
@@ -697,9 +720,9 @@
}
private class MessageHandler extends Handler {
- private Session.Callback mCallback;
+ private MediaSession.Callback mCallback;
- public MessageHandler(Looper looper, Session.Callback callback) {
+ public MessageHandler(Looper looper, MediaSession.Callback callback) {
super(looper, null, true);
mCallback = callback;
}
diff --git a/media/java/android/media/session/SessionInfo.java b/media/java/android/media/session/MediaSessionInfo.java
similarity index 78%
rename from media/java/android/media/session/SessionInfo.java
rename to media/java/android/media/session/MediaSessionInfo.java
index 2b65528..3d8d33f 100644
--- a/media/java/android/media/session/SessionInfo.java
+++ b/media/java/android/media/session/MediaSessionInfo.java
@@ -21,19 +21,19 @@
/**
* Information about a media session, including the owner's package name.
*/
-public final class SessionInfo implements Parcelable {
+public final class MediaSessionInfo implements Parcelable {
private final String mId;
private final String mPackageName;
/**
* @hide
*/
- public SessionInfo(String id, String packageName) {
+ public MediaSessionInfo(String id, String packageName) {
mId = id;
mPackageName = packageName;
}
- private SessionInfo(Parcel in) {
+ private MediaSessionInfo(Parcel in) {
mId = in.readString();
mPackageName = in.readString();
}
@@ -72,16 +72,16 @@
dest.writeString(mPackageName);
}
- public static final Parcelable.Creator<SessionInfo> CREATOR
- = new Parcelable.Creator<SessionInfo>() {
+ public static final Parcelable.Creator<MediaSessionInfo> CREATOR
+ = new Parcelable.Creator<MediaSessionInfo>() {
@Override
- public SessionInfo createFromParcel(Parcel in) {
- return new SessionInfo(in);
+ public MediaSessionInfo createFromParcel(Parcel in) {
+ return new MediaSessionInfo(in);
}
@Override
- public SessionInfo[] newArray(int size) {
- return new SessionInfo[size];
+ public MediaSessionInfo[] newArray(int size) {
+ return new MediaSessionInfo[size];
}
};
}
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index c07229d..2e02a66 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -35,11 +35,12 @@
*/
public class MediaSessionLegacyHelper {
private static final String TAG = "MediaSessionHelper";
+ private static final boolean DEBUG = true;
private static final Object sLock = new Object();
private static MediaSessionLegacyHelper sInstance;
- private SessionManager mSessionManager;
+ private MediaSessionManager mSessionManager;
private Handler mHandler = new Handler(Looper.getMainLooper());
// The legacy APIs use PendingIntents to register/unregister media button
// receivers and these are associated with RCC.
@@ -47,11 +48,14 @@
= new ArrayMap<PendingIntent, SessionHolder>();
private MediaSessionLegacyHelper(Context context) {
- mSessionManager = (SessionManager) context
+ mSessionManager = (MediaSessionManager) context
.getSystemService(Context.MEDIA_SESSION_SERVICE);
}
public static MediaSessionLegacyHelper getHelper(Context context) {
+ if (DEBUG) {
+ Log.d(TAG, "Attempting to get helper with context " + context);
+ }
synchronized (sLock) {
if (sInstance == null) {
sInstance = new MediaSessionLegacyHelper(context);
@@ -60,17 +64,30 @@
return sInstance;
}
- public Session getSession(PendingIntent pi) {
+ public MediaSession getSession(PendingIntent pi) {
SessionHolder holder = mSessions.get(pi);
return holder == null ? null : holder.mSession;
}
- public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+ public void sendMediaButtonEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ mSessionManager.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+ if (DEBUG) {
+ Log.d(TAG, "dispatched media key " + keyEvent);
+ }
+ }
+ public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+ if (pi == null) {
+ Log.w(TAG, "Pending intent was null, can't add rcc listener.");
+ return;
+ }
SessionHolder holder = getHolder(pi, true);
TransportPerformer performer = holder.mSession.getTransportPerformer();
if (holder.mRccListener != null) {
if (holder.mRccListener == listener) {
+ if (DEBUG) {
+ Log.d(TAG, "addRccListener listener already added.");
+ }
// This is already the registered listener, ignore
return;
}
@@ -79,50 +96,82 @@
}
performer.addListener(listener, mHandler);
holder.mRccListener = listener;
- holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+ holder.mFlags |= MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS;
holder.mSession.setFlags(holder.mFlags);
holder.update();
+ if (DEBUG) {
+ Log.d(TAG, "Added rcc listener for " + pi + ".");
+ }
}
public void removeRccListener(PendingIntent pi) {
+ if (pi == null) {
+ return;
+ }
SessionHolder holder = getHolder(pi, false);
if (holder != null && holder.mRccListener != null) {
holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
holder.mRccListener = null;
- holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+ holder.mFlags &= ~MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS;
holder.mSession.setFlags(holder.mFlags);
holder.update();
+ if (DEBUG) {
+ Log.d(TAG, "Removed rcc listener for " + pi + ".");
+ }
}
}
public void addMediaButtonListener(PendingIntent pi,
Context context) {
+ if (pi == null) {
+ Log.w(TAG, "Pending intent was null, can't addMediaButtonListener.");
+ return;
+ }
SessionHolder holder = getHolder(pi, true);
if (holder.mMediaButtonListener != null) {
- // Already have this listener registered
+ // Already have this listener registered, but update it anyway as
+ // the extras may have changed.
+ if (DEBUG) {
+ Log.d(TAG, "addMediaButtonListener already added " + pi);
+ }
return;
}
holder.mMediaButtonListener = new MediaButtonListener(pi, context);
- holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS;
+ holder.mFlags |= MediaSession.FLAG_HANDLES_MEDIA_BUTTONS;
holder.mSession.setFlags(holder.mFlags);
holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
+
+ holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context);
+ holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler);
+ if (DEBUG) {
+ Log.d(TAG, "addMediaButtonListener added " + pi);
+ }
}
public void removeMediaButtonListener(PendingIntent pi) {
+ if (pi == null) {
+ return;
+ }
SessionHolder holder = getHolder(pi, false);
if (holder != null && holder.mMediaButtonListener != null) {
holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
- holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS;
+ holder.mFlags &= ~MediaSession.FLAG_HANDLES_MEDIA_BUTTONS;
holder.mSession.setFlags(holder.mFlags);
holder.mMediaButtonListener = null;
+
+ holder.mSession.removeCallback(holder.mMediaButtonReceiver);
+ holder.mMediaButtonReceiver = null;
holder.update();
+ if (DEBUG) {
+ Log.d(TAG, "removeMediaButtonListener removed " + pi);
+ }
}
}
private SessionHolder getHolder(PendingIntent pi, boolean createIfMissing) {
SessionHolder holder = mSessions.get(pi);
if (holder == null && createIfMissing) {
- Session session = mSessionManager.createSession(TAG);
+ MediaSession session = mSessionManager.createSession(TAG);
session.setActive(true);
holder = new SessionHolder(session, pi);
mSessions.put(pi, holder);
@@ -130,7 +179,32 @@
return holder;
}
- public static class MediaButtonListener extends TransportPerformer.Listener {
+ private static void sendKeyEvent(PendingIntent pi, Context context, Intent intent) {
+ try {
+ pi.send(context, 0, intent);
+ } catch (CanceledException e) {
+ Log.e(TAG, "Error sending media key down event:", e);
+ // Don't bother sending up if down failed
+ return;
+ }
+ }
+
+ private static final class MediaButtonReceiver extends MediaSession.Callback {
+ private final PendingIntent mPendingIntent;
+ private final Context mContext;
+
+ public MediaButtonReceiver(PendingIntent pi, Context context) {
+ mPendingIntent = pi;
+ mContext = context;
+ }
+
+ @Override
+ public void onMediaButton(Intent mediaButtonIntent) {
+ MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, mediaButtonIntent);
+ }
+ }
+
+ private static final class MediaButtonListener extends TransportPerformer.Listener {
private final PendingIntent mPendingIntent;
private final Context mContext;
@@ -179,32 +253,27 @@
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
- try {
- mPendingIntent.send(mContext, 0, intent);
- } catch (CanceledException e) {
- Log.e(TAG, "Error sending media key down event:", e);
- // Don't bother sending up if down failed
- return;
- }
+ MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, intent);
ke = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
- try {
- mPendingIntent.send(mContext, 0, intent);
- } catch (CanceledException e) {
- Log.e(TAG, "Error sending media key up event:", e);
+ MediaSessionLegacyHelper.sendKeyEvent(mPendingIntent, mContext, intent);
+
+ if (DEBUG) {
+ Log.d(TAG, "Sent " + keyCode + " to pending intent " + mPendingIntent);
}
}
}
private class SessionHolder {
- public final Session mSession;
+ public final MediaSession mSession;
public final PendingIntent mPi;
public MediaButtonListener mMediaButtonListener;
+ public MediaButtonReceiver mMediaButtonReceiver;
public TransportPerformer.Listener mRccListener;
public int mFlags;
- public SessionHolder(Session session, PendingIntent pi) {
+ public SessionHolder(MediaSession session, PendingIntent pi) {
mSession = session;
mPi = pi;
}
@@ -213,10 +282,6 @@
if (mMediaButtonListener == null && mRccListener == null) {
mSession.release();
mSessions.remove(mPi);
- } else if (mMediaButtonListener != null && mRccListener != null) {
- // TODO set session to active
- } else {
- // TODO set session to inactive
}
}
}
diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/MediaSessionManager.java
similarity index 72%
rename from media/java/android/media/session/SessionManager.java
rename to media/java/android/media/session/MediaSessionManager.java
index 1eb3b7a..0589a7d 100644
--- a/media/java/android/media/session/SessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -25,6 +25,7 @@
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.util.Log;
+import android.view.KeyEvent;
import java.util.ArrayList;
import java.util.List;
@@ -38,10 +39,10 @@
* get an instance of this class.
* <p>
*
- * @see Session
- * @see SessionController
+ * @see MediaSession
+ * @see MediaController
*/
-public final class SessionManager {
+public final class MediaSessionManager {
private static final String TAG = "SessionManager";
private final ISessionManager mService;
@@ -51,7 +52,7 @@
/**
* @hide
*/
- public SessionManager(Context context) {
+ public MediaSessionManager(Context context) {
// Consider rewriting like DisplayManagerGlobal
// Decide if we need context
mContext = context;
@@ -63,9 +64,9 @@
* Creates a new session.
*
* @param tag A short name for debugging purposes
- * @return a {@link Session} for the new session
+ * @return a {@link MediaSession} for the new session
*/
- public Session createSession(String tag) {
+ public MediaSession createSession(String tag) {
return createSessionAsUser(tag, UserHandle.myUserId());
}
@@ -77,13 +78,13 @@
*
* @param tag A short name for debugging purposes
* @param userId The user id to create the session as.
- * @return a {@link Session} for the new session
+ * @return a {@link MediaSession} for the new session
* @hide
*/
- public Session createSessionAsUser(String tag, int userId) {
+ public MediaSession createSessionAsUser(String tag, int userId) {
try {
- Session.CallbackStub cbStub = new Session.CallbackStub();
- Session session = new Session(mService
+ MediaSession.CallbackStub cbStub = new MediaSession.CallbackStub();
+ MediaSession session = new MediaSession(mService
.createSession(mContext.getPackageName(), cbStub, tag, userId), cbStub);
cbStub.setMediaSession(session);
@@ -106,7 +107,7 @@
* May be null.
* @return A list of controllers for ongoing sessions
*/
- public List<SessionController> getActiveSessions(ComponentName notificationListener) {
+ public List<MediaController> getActiveSessions(ComponentName notificationListener) {
return getActiveSessionsForUser(notificationListener, UserHandle.myUserId());
}
@@ -123,13 +124,13 @@
* @return A list of controllers for ongoing sessions.
* @hide
*/
- public List<SessionController> getActiveSessionsForUser(ComponentName notificationListener,
+ public List<MediaController> getActiveSessionsForUser(ComponentName notificationListener,
int userId) {
- ArrayList<SessionController> controllers = new ArrayList<SessionController>();
+ ArrayList<MediaController> controllers = new ArrayList<MediaController>();
try {
List<IBinder> binders = mService.getSessions(notificationListener, userId);
for (int i = binders.size() - 1; i >= 0; i--) {
- SessionController controller = SessionController.fromBinder(ISessionController.Stub
+ MediaController controller = MediaController.fromBinder(ISessionController.Stub
.asInterface(binders.get(i)));
controllers.add(controller);
}
@@ -138,4 +139,30 @@
}
return controllers;
}
+
+ /**
+ * Send a media key event. The receiver will be selected automatically.
+ *
+ * @param keyEvent The KeyEvent to send.
+ * @hide
+ */
+ public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+ dispatchMediaKeyEvent(keyEvent, false);
+ }
+
+ /**
+ * Send a media key event. The receiver will be selected automatically.
+ *
+ * @param keyEvent The KeyEvent to send
+ * @param needWakeLock true if a wake lock should be held while sending the
+ * key
+ * @hide
+ */
+ public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ try {
+ mService.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send key event.", e);
+ }
+ }
}
diff --git a/media/java/android/media/session/SessionToken.aidl b/media/java/android/media/session/MediaSessionToken.aidl
similarity index 95%
rename from media/java/android/media/session/SessionToken.aidl
rename to media/java/android/media/session/MediaSessionToken.aidl
index db35f85..5812682 100644
--- a/media/java/android/media/session/SessionToken.aidl
+++ b/media/java/android/media/session/MediaSessionToken.aidl
@@ -15,4 +15,4 @@
package android.media.session;
-parcelable SessionToken;
+parcelable MediaSessionToken;
diff --git a/media/java/android/media/session/SessionToken.java b/media/java/android/media/session/MediaSessionToken.java
similarity index 72%
rename from media/java/android/media/session/SessionToken.java
rename to media/java/android/media/session/MediaSessionToken.java
index 59486f6..f5569a4 100644
--- a/media/java/android/media/session/SessionToken.java
+++ b/media/java/android/media/session/MediaSessionToken.java
@@ -20,17 +20,17 @@
import android.os.Parcel;
import android.os.Parcelable;
-public class SessionToken implements Parcelable {
+public class MediaSessionToken implements Parcelable {
private ISessionController mBinder;
/**
* @hide
*/
- SessionToken(ISessionController binder) {
+ MediaSessionToken(ISessionController binder) {
mBinder = binder;
}
- private SessionToken(Parcel in) {
+ private MediaSessionToken(Parcel in) {
mBinder = ISessionController.Stub.asInterface(in.readStrongBinder());
}
@@ -51,16 +51,16 @@
dest.writeStrongBinder(mBinder.asBinder());
}
- public static final Parcelable.Creator<SessionToken> CREATOR
- = new Parcelable.Creator<SessionToken>() {
+ public static final Parcelable.Creator<MediaSessionToken> CREATOR
+ = new Parcelable.Creator<MediaSessionToken>() {
@Override
- public SessionToken createFromParcel(Parcel in) {
- return new SessionToken(in);
+ public MediaSessionToken createFromParcel(Parcel in) {
+ return new MediaSessionToken(in);
}
@Override
- public SessionToken[] newArray(int size) {
- return new SessionToken[size];
+ public MediaSessionToken[] newArray(int size) {
+ return new MediaSessionToken[size];
}
};
}
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 3254e5d..7ef38eaa 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -21,7 +21,7 @@
import android.os.SystemClock;
/**
- * Playback state for a {@link Session}. This includes a state like
+ * Playback state for a {@link MediaSession}. This includes a state like
* {@link PlaybackState#PLAYSTATE_PLAYING}, the current playback position,
* and the current control capabilities.
*/
@@ -160,6 +160,7 @@
* route. Depending on the implementation you may return to the previous
* state when the connection finishes or enter {@link #PLAYSTATE_NONE}. If
* the connection failed {@link #PLAYSTATE_ERROR} should be used.
+ * @hide
*/
public final static int PLAYSTATE_CONNECTING = 8;
diff --git a/media/java/android/media/session/Route.java b/media/java/android/media/session/Route.java
index c9530a6..935eb5b 100644
--- a/media/java/android/media/session/Route.java
+++ b/media/java/android/media/session/Route.java
@@ -28,17 +28,18 @@
* to. The MediaRoute must be used to get {@link RouteInterface}
* instances which can be used to communicate over a specific interface on the
* route.
+ * @hide
*/
public final class Route {
private static final String TAG = "Route";
private final RouteInfo mInfo;
- private final Session mSession;
+ private final MediaSession mSession;
private final RouteOptions mOptions;
/**
* @hide
*/
- public Route(RouteInfo info, RouteOptions options, Session session) {
+ public Route(RouteInfo info, RouteOptions options, MediaSession session) {
if (info == null || options == null) {
throw new IllegalStateException("Route info was not valid!");
}
@@ -93,7 +94,7 @@
/**
* @hide
*/
- Session getSession() {
+ MediaSession getSession() {
return mSession;
}
}
diff --git a/media/java/android/media/session/RouteInfo.java b/media/java/android/media/session/RouteInfo.java
index 17df969..02f78f9 100644
--- a/media/java/android/media/session/RouteInfo.java
+++ b/media/java/android/media/session/RouteInfo.java
@@ -25,6 +25,7 @@
/**
* Information about a route, including its display name, a way to identify it,
* and the ways it can be connected to.
+ * @hide
*/
public final class RouteInfo implements Parcelable {
private final String mName;
diff --git a/media/java/android/media/session/RouteInterface.java b/media/java/android/media/session/RouteInterface.java
index e9c9fd3..8de4d89 100644
--- a/media/java/android/media/session/RouteInterface.java
+++ b/media/java/android/media/session/RouteInterface.java
@@ -25,7 +25,7 @@
import java.util.ArrayList;
/**
- * A route can support multiple interfaces for a {@link Session} to
+ * A route can support multiple interfaces for a {@link MediaSession} to
* interact with. To use a specific interface with a route a
* MediaSessionRouteInterface needs to be retrieved from the route. An
* implementation of the specific interface, like
@@ -33,6 +33,7 @@
* and reduce errors on that interface.
*
* @see RoutePlaybackControls for an example
+ * @hide
*/
public final class RouteInterface {
private static final String TAG = "RouteInterface";
@@ -67,7 +68,7 @@
private final Route mRoute;
private final String mIface;
- private final Session mSession;
+ private final MediaSession mSession;
private final Object mLock = new Object();
private final ArrayList<EventHandler> mListeners = new ArrayList<EventHandler>();
@@ -75,7 +76,7 @@
/**
* @hide
*/
- RouteInterface(Route route, String iface, Session session) {
+ RouteInterface(Route route, String iface, MediaSession session) {
mRoute = route;
mIface = iface;
mSession = session;
diff --git a/media/java/android/media/session/RouteOptions.java b/media/java/android/media/session/RouteOptions.java
index 5105867..b4fb341 100644
--- a/media/java/android/media/session/RouteOptions.java
+++ b/media/java/android/media/session/RouteOptions.java
@@ -34,6 +34,7 @@
* appropriate route options when it is ready to connect to the route. Each
* route options instance must specify a complete set of capabilities to request
* when the connection is established.
+ * @hide
*/
public final class RouteOptions implements Parcelable {
private static final String TAG = "RouteOptions";
diff --git a/media/java/android/media/session/RoutePlaybackControls.java b/media/java/android/media/session/RoutePlaybackControls.java
index a3ffb58..8211983 100644
--- a/media/java/android/media/session/RoutePlaybackControls.java
+++ b/media/java/android/media/session/RoutePlaybackControls.java
@@ -15,6 +15,7 @@
*/
package android.media.session;
+import android.media.MediaMetadata;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
@@ -23,6 +24,7 @@
* A standard media control interface for Routes that support queueing and
* transport controls. Routes may support multiple interfaces for MediaSessions
* to interact with.
+ * @hide
*/
public final class RoutePlaybackControls {
private static final String TAG = "RoutePlaybackControls";
diff --git a/media/java/android/media/session/TransportController.java b/media/java/android/media/session/TransportController.java
index 9574df6..090489b 100644
--- a/media/java/android/media/session/TransportController.java
+++ b/media/java/android/media/session/TransportController.java
@@ -15,6 +15,7 @@
*/
package android.media.session;
+import android.media.MediaMetadata;
import android.media.Rating;
import android.os.Handler;
import android.os.Looper;
diff --git a/media/java/android/media/session/TransportPerformer.java b/media/java/android/media/session/TransportPerformer.java
index 187f48d..1588d8f 100644
--- a/media/java/android/media/session/TransportPerformer.java
+++ b/media/java/android/media/session/TransportPerformer.java
@@ -16,6 +16,7 @@
package android.media.session;
import android.media.AudioManager;
+import android.media.MediaMetadata;
import android.media.Rating;
import android.os.Handler;
import android.os.Looper;
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 90fe695..d658654 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,6 +2,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ android_media_DngCreator.cpp \
android_media_ImageReader.cpp \
android_media_MediaCrypto.cpp \
android_media_MediaCodec.cpp \
@@ -41,6 +42,7 @@
libjhead \
libexif \
libstagefright_amrnb_common \
+ libimg_utils \
LOCAL_REQUIRED_MODULES := \
libjhead_jni
@@ -53,6 +55,7 @@
external/tremor/Tremor \
frameworks/base/core/jni \
frameworks/av/media/libmedia \
+ frameworks/av/media/img_utils/include \
frameworks/av/media/libstagefright \
frameworks/av/media/libstagefright/codecs/amrnb/enc/src \
frameworks/av/media/libstagefright/codecs/amrnb/common \
diff --git a/media/jni/android_media_DngCreator.cpp b/media/jni/android_media_DngCreator.cpp
new file mode 100644
index 0000000..860d896
--- /dev/null
+++ b/media/jni/android_media_DngCreator.cpp
@@ -0,0 +1,772 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DngCreator_JNI"
+
+#include <system/camera_metadata.h>
+#include <camera/CameraMetadata.h>
+#include <img_utils/DngUtils.h>
+#include <img_utils/TagDefinitions.h>
+#include <img_utils/TiffIfd.h>
+#include <img_utils/TiffWriter.h>
+#include <img_utils/Output.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+#include <cutils/properties.h>
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+using namespace android;
+using namespace img_utils;
+
+#define BAIL_IF_INVALID(expr, jnienv, tagId) \
+ if ((expr) != OK) { \
+ jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+ "Invalid metadata for tag %x", tagId); \
+ return; \
+ }
+
+#define BAIL_IF_EMPTY(entry, jnienv, tagId) \
+ if (entry.count == 0) { \
+ jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+ "Missing metadata fields for tag %x", tagId); \
+ return; \
+ }
+
+#define ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID "mNativeContext"
+
+static struct {
+ jfieldID mNativeContext;
+} gDngCreatorClassInfo;
+
+static struct {
+ jmethodID mWriteMethod;
+} gOutputStreamClassInfo;
+
+enum {
+ BITS_PER_SAMPLE = 16,
+ BYTES_PER_SAMPLE = 2,
+ TIFF_IFD_0 = 0
+};
+
+// ----------------------------------------------------------------------------
+
+// This class is not intended to be used across JNI calls.
+class JniOutputStream : public Output, public LightRefBase<JniOutputStream> {
+public:
+ JniOutputStream(JNIEnv* env, jobject outStream);
+
+ virtual ~JniOutputStream();
+
+ status_t open();
+ status_t write(const uint8_t* buf, size_t offset, size_t count);
+ status_t close();
+private:
+ enum {
+ BYTE_ARRAY_LENGTH = 1024
+ };
+ jobject mOutputStream;
+ JNIEnv* mEnv;
+ jbyteArray mByteArray;
+};
+
+JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
+ mEnv(env) {
+ mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
+ if (mByteArray == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
+ }
+}
+
+JniOutputStream::~JniOutputStream() {
+ mEnv->DeleteLocalRef(mByteArray);
+}
+
+status_t JniOutputStream::open() {
+ // Do nothing
+ return OK;
+}
+
+status_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) {
+ while(count > 0) {
+ size_t len = BYTE_ARRAY_LENGTH;
+ len = (count > len) ? len : count;
+ mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset));
+
+ if (mEnv->ExceptionCheck()) {
+ return BAD_VALUE;
+ }
+
+ mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray,
+ 0, len);
+
+ if (mEnv->ExceptionCheck()) {
+ return BAD_VALUE;
+ }
+
+ count -= len;
+ offset += len;
+ }
+ return OK;
+}
+
+status_t JniOutputStream::close() {
+ // Do nothing
+ return OK;
+}
+
+// ----------------------------------------------------------------------------
+
+extern "C" {
+
+static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
+ ALOGV("%s:", __FUNCTION__);
+ return reinterpret_cast<TiffWriter*>(env->GetLongField(thiz,
+ gDngCreatorClassInfo.mNativeContext));
+}
+
+static void DngCreator_setCreator(JNIEnv* env, jobject thiz, sp<TiffWriter> writer) {
+ ALOGV("%s:", __FUNCTION__);
+ TiffWriter* current = DngCreator_getCreator(env, thiz);
+ if (writer != NULL) {
+ writer->incStrong((void*) DngCreator_setCreator);
+ }
+ if (current) {
+ current->decStrong((void*) DngCreator_setCreator);
+ }
+ env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext,
+ reinterpret_cast<jlong>(writer.get()));
+}
+
+static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
+ ALOGV("%s:", __FUNCTION__);
+
+ gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz,
+ ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID, "J");
+ LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL,
+ "can't find android/media/DngCreator.%s", ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID);
+
+ jclass outputStreamClazz = env->FindClass("java/io/OutputStream");
+ LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class");
+ gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V");
+ LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method");
+}
+
+static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
+ jobject resultsPtr) {
+ ALOGV("%s:", __FUNCTION__);
+ CameraMetadata characteristics;
+ CameraMetadata results;
+ if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) {
+ jniThrowException(env, "java/lang/AssertionError",
+ "No native metadata defined for camera characteristics.");
+ return;
+ }
+ if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) {
+ jniThrowException(env, "java/lang/AssertionError",
+ "No native metadata defined for capture results.");
+ return;
+ }
+
+ sp<TiffWriter> writer = new TiffWriter();
+
+ writer->addIfd(TIFF_IFD_0);
+
+ status_t err = OK;
+
+ const uint32_t samplesPerPixel = 1;
+ const uint32_t bitsPerSample = BITS_PER_SAMPLE;
+ const uint32_t bitsPerByte = BITS_PER_SAMPLE / BYTES_PER_SAMPLE;
+ uint32_t imageWidth = 0;
+ uint32_t imageHeight = 0;
+
+ OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
+
+ // TODO: Greensplit.
+ // TODO: UniqueCameraModel
+ // TODO: Add remaining non-essential tags
+ {
+ // Set orientation
+ uint16_t orientation = 1; // Normal
+ BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
+ TAG_ORIENTATION);
+ }
+
+ {
+ // Set subfiletype
+ uint32_t subfileType = 0; // Main image
+ BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
+ TAG_NEWSUBFILETYPE);
+ }
+
+ {
+ // Set bits per sample
+ uint16_t bits = static_cast<uint16_t>(bitsPerSample);
+ BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
+ TAG_BITSPERSAMPLE);
+ }
+
+ {
+ // Set compression
+ uint16_t compression = 1; // None
+ BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
+ TAG_COMPRESSION);
+ }
+
+ {
+ // Set dimensions
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH);
+ uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
+ uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
+ BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
+ TAG_IMAGEWIDTH);
+ BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
+ TAG_IMAGELENGTH);
+ imageWidth = width;
+ imageHeight = height;
+ }
+
+ {
+ // Set photometric interpretation
+ uint16_t interpretation = 32803;
+ BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
+ TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION);
+ }
+
+ {
+ // Set blacklevel tags
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+ BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL);
+ const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
+ BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
+ TAG_BLACKLEVEL);
+
+ uint16_t repeatDim[2] = {2, 2};
+ BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
+ TAG_BLACKLEVELREPEATDIM);
+ }
+
+ {
+ // Set samples per pixel
+ uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
+ BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
+ env, TAG_SAMPLESPERPIXEL);
+ }
+
+ {
+ // Set planar configuration
+ uint16_t config = 1; // Chunky
+ BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
+ env, TAG_PLANARCONFIGURATION);
+ }
+
+ {
+ // Set CFA pattern dimensions
+ uint16_t repeatDim[2] = {2, 2};
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
+ env, TAG_CFAREPEATPATTERNDIM);
+ }
+
+ {
+ // Set CFA pattern
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
+ BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN);
+ camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
+ static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
+ entry.data.u8[0]);
+ switch(cfa) {
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
+ uint8_t cfa[4] = {0, 1, 1, 2};
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+ env, TAG_CFAPATTERN);
+ opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
+ break;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
+ uint8_t cfa[4] = {1, 0, 2, 1};
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+ env, TAG_CFAPATTERN);
+ opcodeCfaLayout = OpcodeListBuilder::CFA_GRBG;
+ break;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
+ uint8_t cfa[4] = {1, 2, 0, 1};
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+ env, TAG_CFAPATTERN);
+ opcodeCfaLayout = OpcodeListBuilder::CFA_GBRG;
+ break;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
+ uint8_t cfa[4] = {2, 1, 1, 0};
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+ env, TAG_CFAPATTERN);
+ opcodeCfaLayout = OpcodeListBuilder::CFA_BGGR;
+ break;
+ }
+ default: {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Invalid metadata for tag %d", TAG_CFAPATTERN);
+ return;
+ }
+ }
+ }
+
+ {
+ // Set CFA plane color
+ uint8_t cfaPlaneColor[3] = {0, 1, 2};
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
+ env, TAG_CFAPLANECOLOR);
+ }
+
+ {
+ // Set CFA layout
+ uint16_t cfaLayout = 1;
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
+ env, TAG_CFALAYOUT);
+ }
+
+ {
+ // Set DNG version information
+ uint8_t version[4] = {1, 4, 0, 0};
+ BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
+ env, TAG_DNGVERSION);
+
+ uint8_t backwardVersion[4] = {1, 1, 0, 0};
+ BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
+ env, TAG_DNGBACKWARDVERSION);
+ }
+
+ {
+ // Set whitelevel
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
+ BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL);
+ uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
+ BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
+ TAG_WHITELEVEL);
+ }
+
+ {
+ // Set default scale
+ uint32_t defaultScale[4] = {1, 1, 1, 1};
+ BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
+ env, TAG_DEFAULTSCALE);
+ }
+
+ bool singleIlluminant = false;
+ {
+ // Set calibration illuminants
+ camera_metadata_entry entry1 =
+ characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
+ BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1);
+ camera_metadata_entry entry2 =
+ characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
+ if (entry2.count == 0) {
+ singleIlluminant = true;
+ }
+ uint16_t ref1 = entry1.data.u8[0];
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
+ TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1);
+
+ if (!singleIlluminant) {
+ uint16_t ref2 = entry2.data.u8[0];
+ BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
+ TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2);
+ }
+ }
+
+ {
+ // Set color transforms
+ camera_metadata_entry entry1 =
+ characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
+ BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1);
+
+ int32_t colorTransform1[entry1.count * 2];
+
+ size_t ctr = 0;
+ for(size_t i = 0; i < entry1.count; ++i) {
+ colorTransform1[ctr++] = entry1.data.r[i].numerator;
+ colorTransform1[ctr++] = entry1.data.r[i].denominator;
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1, TIFF_IFD_0),
+ env, TAG_COLORMATRIX1);
+
+ if (!singleIlluminant) {
+ camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
+ BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2);
+ int32_t colorTransform2[entry2.count * 2];
+
+ ctr = 0;
+ for(size_t i = 0; i < entry2.count; ++i) {
+ colorTransform2[ctr++] = entry2.data.r[i].numerator;
+ colorTransform2[ctr++] = entry2.data.r[i].denominator;
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2, TIFF_IFD_0),
+ env, TAG_COLORMATRIX2);
+ }
+ }
+
+ {
+ // Set calibration transforms
+ camera_metadata_entry entry1 =
+ characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
+ BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1);
+
+ int32_t calibrationTransform1[entry1.count * 2];
+
+ size_t ctr = 0;
+ for(size_t i = 0; i < entry1.count; ++i) {
+ calibrationTransform1[ctr++] = entry1.data.r[i].numerator;
+ calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1,
+ TIFF_IFD_0), env, TAG_CAMERACALIBRATION1);
+
+ if (!singleIlluminant) {
+ camera_metadata_entry entry2 =
+ characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
+ BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2);
+ int32_t calibrationTransform2[entry2.count * 2];
+
+ ctr = 0;
+ for(size_t i = 0; i < entry2.count; ++i) {
+ calibrationTransform2[ctr++] = entry2.data.r[i].numerator;
+ calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1,
+ TIFF_IFD_0), env, TAG_CAMERACALIBRATION2);
+ }
+ }
+
+ {
+ // Set forward transforms
+ camera_metadata_entry entry1 =
+ characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
+ BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1);
+
+ int32_t forwardTransform1[entry1.count * 2];
+
+ size_t ctr = 0;
+ for(size_t i = 0; i < entry1.count; ++i) {
+ forwardTransform1[ctr++] = entry1.data.r[i].numerator;
+ forwardTransform1[ctr++] = entry1.data.r[i].denominator;
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
+ TIFF_IFD_0), env, TAG_FORWARDMATRIX1);
+
+ if (!singleIlluminant) {
+ camera_metadata_entry entry2 =
+ characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
+ BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2);
+ int32_t forwardTransform2[entry2.count * 2];
+
+ ctr = 0;
+ for(size_t i = 0; i < entry2.count; ++i) {
+ forwardTransform2[ctr++] = entry2.data.r[i].numerator;
+ forwardTransform2[ctr++] = entry2.data.r[i].denominator;
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
+ TIFF_IFD_0), env, TAG_FORWARDMATRIX2);
+ }
+ }
+
+ {
+ // Set camera neutral
+ camera_metadata_entry entry =
+ results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
+ BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL);
+ uint32_t cameraNeutral[entry.count * 2];
+
+ size_t ctr = 0;
+ for(size_t i = 0; i < entry.count; ++i) {
+ cameraNeutral[ctr++] =
+ static_cast<uint32_t>(entry.data.r[i].numerator);
+ cameraNeutral[ctr++] =
+ static_cast<uint32_t>(entry.data.r[i].denominator);
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
+ TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL);
+ }
+
+ {
+ // Setup data strips
+ // TODO: Switch to tiled implementation.
+ uint32_t offset = 0;
+ BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &offset, TIFF_IFD_0), env,
+ TAG_STRIPOFFSETS);
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_ROWSPERSTRIP, 1, &imageHeight, TIFF_IFD_0), env,
+ TAG_ROWSPERSTRIP);
+
+ uint32_t byteCount = imageWidth * imageHeight * bitsPerSample * samplesPerPixel /
+ bitsPerByte;
+ BAIL_IF_INVALID(writer->addEntry(TAG_STRIPBYTECOUNTS, 1, &byteCount, TIFF_IFD_0), env,
+ TAG_STRIPBYTECOUNTS);
+ }
+
+ {
+ // Setup default crop + crop origin tags
+ uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
+ uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
+ if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
+ uint32_t defaultCropOrigin[] = {margin, margin};
+ uint32_t defaultCropSize[] = {imageWidth - margin, imageHeight - margin};
+ BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
+ TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN);
+ BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
+ TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE);
+ }
+ }
+
+ {
+ // Setup unique camera model tag
+ char model[PROPERTY_VALUE_MAX];
+ property_get("ro.product.model", model, "");
+
+ char manufacturer[PROPERTY_VALUE_MAX];
+ property_get("ro.product.manufacturer", manufacturer, "");
+
+ char brand[PROPERTY_VALUE_MAX];
+ property_get("ro.product.brand", brand, "");
+
+ String8 cameraModel(model);
+ cameraModel += "-";
+ cameraModel += manufacturer;
+ cameraModel += "-";
+ cameraModel += brand;
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
+ reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
+ TAG_UNIQUECAMERAMODEL);
+ }
+
+ {
+ // Setup opcode List 2
+ camera_metadata_entry entry1 =
+ characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+ BAIL_IF_EMPTY(entry1, env, TAG_OPCODELIST2);
+ uint32_t lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]);
+ uint32_t lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]);
+
+ camera_metadata_entry entry2 =
+ results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+ BAIL_IF_EMPTY(entry2, env, TAG_OPCODELIST2);
+ if (entry2.count == lsmWidth * lsmHeight * 4) {
+
+ OpcodeListBuilder builder;
+ status_t err = builder.addGainMapsForMetadata(lsmWidth,
+ lsmHeight,
+ 0,
+ 0,
+ imageHeight,
+ imageWidth,
+ opcodeCfaLayout,
+ entry2.data.f);
+ if (err == OK) {
+ size_t listSize = builder.getSize();
+ uint8_t opcodeListBuf[listSize];
+ err = builder.buildOpList(opcodeListBuf);
+ if (err == OK) {
+ BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
+ TIFF_IFD_0), env, TAG_OPCODELIST2);
+ } else {
+ ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__);
+ jniThrowRuntimeException(env, "failed to construct lens shading map opcode.");
+ }
+ } else {
+ ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
+ jniThrowRuntimeException(env, "failed to add lens shading map.");
+ }
+ } else {
+ ALOGW("%s: Lens shading map not present in results, skipping...", __FUNCTION__);
+ }
+ }
+
+ DngCreator_setCreator(env, thiz, writer);
+}
+
+static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
+ ALOGV("%s:", __FUNCTION__);
+ DngCreator_setCreator(env, thiz, NULL);
+}
+
+static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz) {
+ ALOGV("%s:", __FUNCTION__);
+ jniThrowRuntimeException(env, "nativeSetOrientation is not implemented");
+}
+
+static void DngCreator_nativeSetThumbnailBitmap(JNIEnv* env, jobject thiz, jobject bitmap) {
+ ALOGV("%s:", __FUNCTION__);
+ jniThrowRuntimeException(env, "nativeSetThumbnailBitmap is not implemented");
+}
+
+static void DngCreator_nativeSetThumbnailImage(JNIEnv* env, jobject thiz, jint width, jint height,
+ jobject yBuffer, jint yRowStride, jint yPixStride, jobject uBuffer, jint uRowStride,
+ jint uPixStride, jobject vBuffer, jint vRowStride, jint vPixStride) {
+ ALOGV("%s:", __FUNCTION__);
+ jniThrowRuntimeException(env, "nativeSetThumbnailImage is not implemented");
+}
+
+static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width,
+ jint height, jobject inBuffer, jint rowStride, jint pixStride) {
+ ALOGV("%s:", __FUNCTION__);
+
+ sp<JniOutputStream> out = new JniOutputStream(env, outStream);
+ if(env->ExceptionCheck()) {
+ ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
+ return;
+ }
+
+ uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
+ if (pixelBytes == NULL) {
+ ALOGE("%s: Could not get native byte buffer", __FUNCTION__);
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid bytebuffer");
+ return;
+ }
+
+ TiffWriter* writer = DngCreator_getCreator(env, thiz);
+ if (writer == NULL) {
+ ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+ jniThrowException(env, "java/lang/AssertionError",
+ "Write called with uninitialized DngCreator");
+ return;
+ }
+ // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
+ uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, TIFF_IFD_0)->getData<uint32_t>());
+ uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, TIFF_IFD_0)->getData<uint32_t>());
+ if (metadataWidth != width) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
+ "Metadata width %d doesn't match image width %d", metadataWidth, width);
+ return;
+ }
+
+ if (metadataHeight != height) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
+ "Metadata height %d doesn't match image height %d", metadataHeight, height);
+ return;
+ }
+
+ uint32_t stripOffset = writer->getTotalSize();
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &stripOffset, TIFF_IFD_0), env,
+ TAG_STRIPOFFSETS);
+
+ if (writer->write(out.get()) != OK) {
+ if (!env->ExceptionCheck()) {
+ jniThrowException(env, "java/io/IOException", "Failed to write metadata");
+ }
+ return;
+ }
+
+ size_t fullSize = rowStride * height;
+ jlong capacity = env->GetDirectBufferCapacity(inBuffer);
+ if (capacity < 0 || fullSize > capacity) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Invalid size %d for Image, size given in metadata is %d at current stride",
+ capacity, fullSize);
+ return;
+ }
+
+ if (pixStride == BYTES_PER_SAMPLE && rowStride == width * BYTES_PER_SAMPLE) {
+ if (out->write(pixelBytes, 0, fullSize) != OK || env->ExceptionCheck()) {
+ if (!env->ExceptionCheck()) {
+ jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+ }
+ return;
+ }
+ } else if (pixStride == BYTES_PER_SAMPLE) {
+ for (size_t i = 0; i < height; ++i) {
+ if (out->write(pixelBytes, i * rowStride, pixStride * width) != OK ||
+ env->ExceptionCheck()) {
+ if (!env->ExceptionCheck()) {
+ jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+ }
+ return;
+ }
+ }
+ } else {
+ for (size_t i = 0; i < height; ++i) {
+ for (size_t j = 0; j < width; ++j) {
+ if (out->write(pixelBytes, i * rowStride + j * pixStride,
+ BYTES_PER_SAMPLE) != OK || !env->ExceptionCheck()) {
+ if (env->ExceptionCheck()) {
+ jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+ }
+ return;
+ }
+ }
+ }
+ }
+
+}
+
+static void DngCreator_nativeWriteByteBuffer(JNIEnv* env, jobject thiz, jobject outStream,
+ jobject rawBuffer, jlong offset) {
+ ALOGV("%s:", __FUNCTION__);
+ jniThrowRuntimeException(env, "nativeWriteByteBuffer is not implemented.");
+}
+
+static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream,
+ jobject inStream, jlong offset) {
+ ALOGV("%s:", __FUNCTION__);
+ jniThrowRuntimeException(env, "nativeWriteInputStream is not implemented.");
+}
+
+} /*extern "C" */
+
+static JNINativeMethod gDngCreatorMethods[] = {
+ {"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit},
+ {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
+ "Landroid/hardware/camera2/impl/CameraMetadataNative;)V", (void*) DngCreator_init},
+ {"nativeDestroy", "()V", (void*) DngCreator_destroy},
+ {"nativeSetOrientation", "(I)V", (void*) DngCreator_nativeSetOrientation},
+ {"nativeSetThumbnailBitmap","(Landroid/graphics/Bitmap;)V",
+ (void*) DngCreator_nativeSetThumbnailBitmap},
+ {"nativeSetThumbnailImage",
+ "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)V",
+ (void*) DngCreator_nativeSetThumbnailImage},
+ {"nativeWriteImage", "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;II)V",
+ (void*) DngCreator_nativeWriteImage},
+ {"nativeWriteByteBuffer", "(Ljava/io/OutputStream;Ljava/nio/ByteBuffer;J)V",
+ (void*) DngCreator_nativeWriteByteBuffer},
+ {"nativeWriteInputStream", "(Ljava/io/OutputStream;Ljava/io/InputStream;J)V",
+ (void*) DngCreator_nativeWriteInputStream},
+};
+
+int register_android_media_DngCreator(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods));
+}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 6f42057..9d03cc38 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -884,6 +884,7 @@
"android/media/MediaPlayer", gMethods, NELEM(gMethods));
}
+extern int register_android_media_DngCreator(JNIEnv *env);
extern int register_android_media_ImageReader(JNIEnv *env);
extern int register_android_media_Crypto(JNIEnv *env);
extern int register_android_media_Drm(JNIEnv *env);
@@ -913,6 +914,11 @@
}
assert(env != NULL);
+ if (register_android_media_DngCreator(env) < 0) {
+ ALOGE("ERROR: ImageReader native registration failed");
+ goto bail;
+ }
+
if (register_android_media_ImageReader(env) < 0) {
ALOGE("ERROR: ImageReader native registration failed");
goto bail;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 89886ef..8a7e642 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -23,10 +23,10 @@
import android.hardware.IProCameraCallbacks;
import android.hardware.IProCameraUser;
import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.utils.BinderHolder;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.os.Binder;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 74ce997..7b2e7dd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -21,10 +21,10 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.utils.BinderHolder;
import android.media.Image;
import android.media.ImageReader;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 5ab586f..a77b647 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -18,6 +18,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Range;
+import android.util.Rational;
import android.util.SizeF;
import android.graphics.ImageFormat;
import android.graphics.Point;
@@ -26,15 +27,14 @@
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.ColorSpaceTransform;
-import android.hardware.camera2.Face;
-import android.hardware.camera2.MeteringRectangle;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.RggbChannelVector;
-import android.hardware.camera2.Size;
+import android.util.Size;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.params.ColorSpaceTransform;
+import android.hardware.camera2.params.Face;
+import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.RggbChannelVector;
import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.params.StreamConfigurationDuration;
import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
index 9621f92..18c0d3e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -17,7 +17,7 @@
package com.android.mediaframeworktest.unit;
import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.camera2.Rational;
+import android.util.Rational;
/**
* <pre>
diff --git a/packages/InputDevices/res/raw/keyboard_layout_danish.kcm b/packages/InputDevices/res/raw/keyboard_layout_danish.kcm
index 9386a45..9168d12 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_danish.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_danish.kcm
@@ -13,13 +13,11 @@
# limitations under the License.
#
-# Danish keyboard layout.
+# Danish (EU based + Sami) keyboard layout.
#
type OVERLAY
-map key 12 SLASH
-map key 53 MINUS
map key 86 PLUS
### ROW 1
@@ -61,6 +59,7 @@
label: '5'
base: '5'
shift: '%'
+ ralt: '\u20ac'
}
key 6 {
@@ -97,7 +96,7 @@
ralt: '}'
}
-key SLASH {
+key MINUS {
label: '+'
base: '+'
shift: '?'
@@ -116,6 +115,8 @@
label: 'Q'
base: 'q'
shift, capslock: 'Q'
+ ralt: '\u00e2'
+ ralt+capslock, shift+ralt: '\u00c2'
}
key W {
@@ -129,6 +130,7 @@
base: 'e'
shift, capslock: 'E'
ralt: '\u20ac'
+ ralt+capslock: '\u20ac'
}
key R {
@@ -141,6 +143,8 @@
label: 'T'
base: 't'
shift, capslock: 'T'
+ ralt: '\u0167'
+ ralt+capslock, shift+ralt: '\u0166'
}
key Y {
@@ -159,12 +163,16 @@
label: 'I'
base: 'i'
shift, capslock: 'I'
+ ralt: '\u00ef'
+ ralt+capslock, shift+ralt: '\u00cf'
}
key O {
label: 'O'
base: 'o'
shift, capslock: 'O'
+ ralt: '\u00f5'
+ ralt+capslock, shift+ralt: '\u00d5'
}
key P {
@@ -192,36 +200,48 @@
label: 'A'
base: 'a'
shift, capslock: 'A'
+ ralt: '\u00e1'
+ ralt+capslock, shift+ralt: '\u00c1'
}
key S {
label: 'S'
base: 's'
shift, capslock: 'S'
+ ralt: '\u0161'
+ ralt+capslock, shift+ralt: '\u0160'
}
key D {
label: 'D'
base: 'd'
shift, capslock: 'D'
+ ralt: '\u0111'
+ ralt+capslock, shift+ralt: '\u0110'
}
key F {
label: 'F'
base: 'f'
shift, capslock: 'F'
+ ralt: '\u01e5'
+ ralt+capslock, shift+ralt: '\u01e4'
}
key G {
label: 'G'
base: 'g'
shift, capslock: 'G'
+ ralt: '\u01e7'
+ ralt+capslock, shift+ralt: '\u01e6'
}
key H {
label: 'H'
base: 'h'
shift, capslock: 'H'
+ ralt: '\u021f'
+ ralt+capslock, shift+ralt: '\u021e'
}
key J {
@@ -234,6 +254,8 @@
label: 'K'
base: 'k'
shift, capslock: 'K'
+ ralt: '\u01e9'
+ ralt+capslock, shift+ralt: '\u01e8'
}
key L {
@@ -246,12 +268,16 @@
label: '\u00c6'
base: '\u00e6'
shift, capslock: '\u00c6'
+ ralt: '\u00e4'
+ ralt+capslock, shift+ralt: '\u00c4'
}
key APOSTROPHE {
label: '\u00d8'
base: '\u00f8'
shift, capslock: '\u00d8'
+ ralt: '\u00f6'
+ ralt+capslock, shift+ralt: '\u00d6'
}
key BACKSLASH {
@@ -273,6 +299,8 @@
label: 'Z'
base: 'z'
shift, capslock: 'Z'
+ ralt: '\u017e'
+ ralt+capslock, shift+ralt: '\u017d'
}
key X {
@@ -285,31 +313,39 @@
label: 'C'
base: 'c'
shift, capslock: 'C'
+ ralt: '\u010d'
+ ralt+capslock, shift+ralt: '\u010c'
}
key V {
label: 'V'
base: 'v'
shift, capslock: 'V'
+ ralt: '\u01ef'
+ ralt+capslock, shift+ralt: '\u01ee'
}
key B {
label: 'B'
base: 'b'
shift, capslock: 'B'
+ ralt: '\u0292'
+ ralt+capslock, shift+ralt: '\u01b7'
}
key N {
label: 'N'
base: 'n'
shift, capslock: 'N'
+ ralt: '\u014b'
+ ralt+capslock, shift+ralt: '\u014a'
}
key M {
label: 'M'
base: 'm'
shift, capslock: 'M'
- ralt: '\u00b5'
+ ralt, ralt+capslock: '\u00b5'
}
key COMMA {
@@ -324,7 +360,7 @@
shift: ':'
}
-key MINUS {
+key SLASH {
label: '-'
base: '-'
shift: '_'
diff --git a/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm b/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm
index c6e5ac4..b4deed4 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_finnish.kcm
@@ -13,13 +13,11 @@
# limitations under the License.
#
-# Finnish multilingual keyboard layout.
+# Finnish (& Swedish)(EU based + Sami) keyboard layout.
#
type OVERLAY
-map key 12 SLASH
-map key 53 MINUS
map key 86 PLUS
### ROW 1
@@ -28,14 +26,12 @@
label: '\u00a7'
base: '\u00a7'
shift: '\u00bd'
- ralt: '\u0335'
}
key 1 {
label: '1'
base: '1'
shift: '!'
- ralt+shift: '\u00a1'
}
key 2 {
@@ -43,7 +39,6 @@
base: '2'
shift: '"'
ralt: '@'
- ralt+shift: '\u201d'
}
key 3 {
@@ -51,7 +46,6 @@
base: '3'
shift: '#'
ralt: '\u00a3'
- ralt+shift: '\u00bb'
}
key 4 {
@@ -59,23 +53,19 @@
base: '4'
shift: '\u00a4'
ralt: '$'
- ralt+shift: '\u00ab'
}
key 5 {
label: '5'
base: '5'
shift: '%'
- ralt: '\u2030'
- ralt+shift: '\u201c'
+ ralt: '\u20ac'
}
key 6 {
label: '6'
base: '6'
shift: '&'
- ralt: '\u201a'
- ralt+shift: '\u201e'
}
key 7 {
@@ -104,23 +94,19 @@
base: '0'
shift: '='
ralt: '}'
- ralt+shift: '\u00b0'
}
-key SLASH {
+key MINUS {
label: '+'
base: '+'
shift: '?'
ralt: '\\'
- ralt+shift: '\u00bf'
}
key EQUALS {
label: '\u00b4'
base: '\u0301'
shift: '\u0300'
- ralt: '\u0327'
- ralt+shift: '\u0328'
}
### ROW 2
@@ -129,6 +115,8 @@
label: 'Q'
base: 'q'
shift, capslock: 'Q'
+ ralt: '\u00e2'
+ ralt+capslock, shift+ralt: '\u00c2'
}
key W {
@@ -142,6 +130,7 @@
base: 'e'
shift, capslock: 'E'
ralt: '\u20ac'
+ ralt+capslock: '\u20ac'
}
key R {
@@ -154,8 +143,8 @@
label: 'T'
base: 't'
shift, capslock: 'T'
- ralt: '\u00fe'
- ralt+shift, ralt+capslock: '\u00de'
+ ralt: '\u0167'
+ ralt+capslock, shift+ralt: '\u0166'
}
key Y {
@@ -174,31 +163,28 @@
label: 'I'
base: 'i'
shift, capslock: 'I'
- ralt: '\u0131'
+ ralt: '\u00ef'
+ ralt+capslock, shift+ralt: '\u00cf'
}
key O {
label: 'O'
base: 'o'
shift, capslock: 'O'
- ralt: '\u0153'
- ralt+shift, ralt+capslock: '\u0152'
+ ralt: '\u00f5'
+ ralt+capslock, shift+ralt: '\u00d5'
}
key P {
label: 'P'
base: 'p'
shift, capslock: 'P'
- ralt: '\u031b'
- ralt+shift: '\u0309'
}
key LEFT_BRACKET {
label: '\u00c5'
base: '\u00e5'
shift, capslock: '\u00c5'
- ralt: '\u030b'
- ralt+shift: '\u030a'
}
key RIGHT_BRACKET {
@@ -206,7 +192,6 @@
base: '\u0308'
shift: '\u0302'
ralt: '\u0303'
- ralt+shift: '\u0304'
}
### ROW 3
@@ -215,41 +200,48 @@
label: 'A'
base: 'a'
shift, capslock: 'A'
- ralt: '\u0259'
- ralt+shift, ralt+capslock: '\u018f'
+ ralt: '\u00e1'
+ ralt+capslock, shift+ralt: '\u00c1'
}
key S {
label: 'S'
base: 's'
shift, capslock: 'S'
- ralt: '\u00df'
+ ralt: '\u0161'
+ ralt+capslock, shift+ralt: '\u0160'
}
key D {
label: 'D'
base: 'd'
shift, capslock: 'D'
- ralt: '\u00f0'
- ralt+shift, ralt+capslock: '\u00d0'
+ ralt: '\u0111'
+ ralt+capslock, shift+ralt: '\u0110'
}
key F {
label: 'F'
base: 'f'
shift, capslock: 'F'
+ ralt: '\u01e5'
+ ralt+capslock, shift+ralt: '\u01e4'
}
key G {
label: 'G'
base: 'g'
shift, capslock: 'G'
+ ralt: '\u01e7'
+ ralt+capslock, shift+ralt: '\u01e6'
}
key H {
label: 'H'
base: 'h'
shift, capslock: 'H'
+ ralt: '\u021f'
+ ralt+capslock, shift+ralt: '\u021e'
}
key J {
@@ -262,14 +254,14 @@
label: 'K'
base: 'k'
shift, capslock: 'K'
- ralt: '\u0138'
+ ralt: '\u01e9'
+ ralt+capslock, shift+ralt: '\u01e8'
}
key L {
label: 'L'
base: 'l'
shift, capslock: 'L'
- ralt: '\u0335'
}
key SEMICOLON {
@@ -277,7 +269,7 @@
base: '\u00f6'
shift, capslock: '\u00d6'
ralt: '\u00f8'
- ralt+shift, ralt+capslock: '\u00d8'
+ ralt+capslock, shift+ralt: '\u00d8'
}
key APOSTROPHE {
@@ -285,15 +277,13 @@
base: '\u00e4'
shift, capslock: '\u00c4'
ralt: '\u00e6'
- ralt+shift, ralt+capslock: '\u00c6'
+ ralt+capslock, shift+ralt: '\u00c6'
}
key BACKSLASH {
label: '\''
base: '\''
shift: '*'
- ralt: '\u030c'
- ralt+shift: '\u0306'
}
### ROW 4
@@ -309,34 +299,38 @@
label: 'Z'
base: 'z'
shift, capslock: 'Z'
- ralt: '\u0292'
- ralt+shift, ralt+capslock: '\u01b7'
+ ralt: '\u017e'
+ ralt+capslock, shift+ralt: '\u017d'
}
key X {
label: 'X'
base: 'x'
shift, capslock: 'X'
- ralt: '\u00d7'
- ralt+shift: '\u00b7'
}
key C {
label: 'C'
base: 'c'
shift, capslock: 'C'
+ ralt: '\u010d'
+ ralt+capslock, shift+ralt: '\u010c'
}
key V {
label: 'V'
base: 'v'
shift, capslock: 'V'
+ ralt: '\u01ef'
+ ralt+capslock, shift+ralt: '\u01ee'
}
key B {
label: 'B'
base: 'b'
shift, capslock: 'B'
+ ralt: '\u0292'
+ ralt+capslock, shift+ralt: '\u01b7'
}
key N {
@@ -344,37 +338,30 @@
base: 'n'
shift, capslock: 'N'
ralt: '\u014b'
- ralt+shift, ralt+capslock: '\u014a'
+ ralt+capslock, shift+ralt: '\u014a'
}
key M {
label: 'M'
base: 'm'
shift, capslock: 'M'
- ralt: '\u00b5'
- ralt+shift: '\u2014'
+ ralt, ralt+capslock: '\u00b5'
}
key COMMA {
label: ','
base: ','
shift: ';'
- ralt: '\u2019'
- ralt+shift: '\u2018'
}
key PERIOD {
label: '.'
base: '.'
shift: ':'
- ralt: '\u0323'
- ralt+shift: '\u0307'
}
-key MINUS {
+key SLASH {
label: '-'
base: '-'
shift: '_'
- ralt: '\u2013'
- ralt+shift: '\u0307'
}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm b/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm
new file mode 100644
index 0000000..d4bc0c0
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm
@@ -0,0 +1,362 @@
+# 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.
+
+#
+# Latvian (QWERTY-US-intl based) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 BACKSLASH
+map key 43 POUND
+
+### ROW 1
+
+key GRAVE {
+ label: '\u0300'
+ base: '\u0300'
+ shift: '\u0303'
+ ralt: '-'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+ ralt: '\u00a0'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '@'
+ ralt: '\u00ab'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '#'
+ ralt: '\u00bb'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+ ralt: '\u20ac'
+ ralt+shift: '\u00a7'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+ ralt+shift: '\u00b0'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '\u0302'
+ ralt: '\u2019'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '&'
+ ralt+shift: '\u00b1'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '*'
+ ralt+shift: '\u00d7'
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: '('
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: ')'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+ ralt: '\u2013'
+ ralt+shift: '\u2014'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u0113'
+ shift+ralt, ralt+capslock: '\u0112'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+ ralt: '\u0157'
+ shift+ralt, ralt+capslock: '\u0156'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+ ralt: '\u016b'
+ shift+ralt, ralt+capslock: '\u016a'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+ ralt: '\u012b'
+ shift+ralt, ralt+capslock: '\u012a'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+ ralt: '\u00f5'
+ shift+ralt, ralt+capslock: '\u00d5'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '['
+ base: '['
+ shift: '{'
+}
+
+key RIGHT_BRACKET {
+ label: ']'
+ base: ']'
+ shift: '}'
+}
+
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+ ralt: '\u0101'
+ shift+ralt, ralt+capslock: '\u0100'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+ ralt: '\u0161'
+ shift+ralt, ralt+capslock: '\u0160'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+ ralt: '\u0123'
+ shift+ralt, ralt+capslock: '\u0122'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+ ralt: '\u0137'
+ shift+ralt, ralt+capslock: '\u0136'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+ ralt: '\u013c'
+ shift+ralt, ralt+capslock: '\u013b'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: ':'
+}
+
+key APOSTROPHE {
+ label: '\''
+ base: '\''
+ shift: '"'
+ ralt: '\u0301'
+ shift+ralt: '\u0308'
+}
+
+key POUND {
+ label: '\u00b0'
+ base: '\u00b0'
+ shift: '|'
+}
+
+### ROW 4
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+ ralt: '\u00ac'
+ shift+ralt: '\u00a6'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+ ralt: '\u017e'
+ shift+ralt, ralt+capslock: '\u017d'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+ ralt: '\u010d'
+ shift+ralt, ralt+capslock: '\u010c'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+ ralt: '\u0146'
+ shift+ralt, ralt+capslock: '\u0145'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '<'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: '>'
+}
+
+key SLASH {
+ label: '/'
+ base: '/'
+ shift: '?'
+ ralt: '\u00bf'
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm b/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm
index d1be485..560dd16 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_norwegian.kcm
@@ -13,13 +13,11 @@
# limitations under the License.
#
-# Norwegian keyboard layout.
+# Norwegian (EU based + Sami) keyboard layout.
#
type OVERLAY
-map key 12 SLASH
-map key 53 MINUS
map key 86 PLUS
### ROW 1
@@ -61,6 +59,7 @@
label: '5'
base: '5'
shift: '%'
+ ralt: '\u20ac'
}
key 6 {
@@ -97,7 +96,7 @@
ralt: '}'
}
-key SLASH {
+key MINUS {
label: '+'
base: '+'
shift: '?'
@@ -116,6 +115,8 @@
label: 'Q'
base: 'q'
shift, capslock: 'Q'
+ ralt: '\u00e2'
+ ralt+capslock, shift+ralt: '\u00c2'
}
key W {
@@ -129,6 +130,7 @@
base: 'e'
shift, capslock: 'E'
ralt: '\u20ac'
+ ralt+capslock: '\u20ac'
}
key R {
@@ -141,6 +143,8 @@
label: 'T'
base: 't'
shift, capslock: 'T'
+ ralt: '\u0167'
+ ralt+capslock, shift+ralt: '\u0166'
}
key Y {
@@ -159,12 +163,16 @@
label: 'I'
base: 'i'
shift, capslock: 'I'
+ ralt: '\u00ef'
+ ralt+capslock, shift+ralt: '\u00cf'
}
key O {
label: 'O'
base: 'o'
shift, capslock: 'O'
+ ralt: '\u00f5'
+ ralt+capslock, shift+ralt: '\u00d5'
}
key P {
@@ -192,36 +200,48 @@
label: 'A'
base: 'a'
shift, capslock: 'A'
+ ralt: '\u00e1'
+ ralt+capslock, shift+ralt: '\u00c1'
}
key S {
label: 'S'
base: 's'
shift, capslock: 'S'
+ ralt: '\u0161'
+ ralt+capslock, shift+ralt: '\u0160'
}
key D {
label: 'D'
base: 'd'
shift, capslock: 'D'
+ ralt: '\u0111'
+ ralt+capslock, shift+ralt: '\u0110'
}
key F {
label: 'F'
base: 'f'
shift, capslock: 'F'
+ ralt: '\u01e5'
+ ralt+capslock, shift+ralt: '\u01e4'
}
key G {
label: 'G'
base: 'g'
shift, capslock: 'G'
+ ralt: '\u01e7'
+ ralt+capslock, shift+ralt: '\u01e6'
}
key H {
label: 'H'
base: 'h'
shift, capslock: 'H'
+ ralt: '\u021f'
+ ralt+capslock, shift+ralt: '\u021e'
}
key J {
@@ -234,6 +254,8 @@
label: 'K'
base: 'k'
shift, capslock: 'K'
+ ralt: '\u01e9'
+ ralt+capslock, shift+ralt: '\u01e8'
}
key L {
@@ -246,12 +268,16 @@
label: '\u00d8'
base: '\u00f8'
shift, capslock: '\u00d8'
+ ralt: '\u00f6'
+ ralt+capslock, shift+ralt: '\u00d6'
}
key APOSTROPHE {
label: '\u00c6'
base: '\u00e6'
shift, capslock: '\u00c6'
+ ralt: '\u00e4'
+ ralt+capslock, shift+ralt: '\u00c4'
}
key BACKSLASH {
@@ -272,6 +298,8 @@
label: 'Z'
base: 'z'
shift, capslock: 'Z'
+ ralt: '\u017e'
+ ralt+capslock, shift+ralt: '\u017d'
}
key X {
@@ -284,31 +312,39 @@
label: 'C'
base: 'c'
shift, capslock: 'C'
+ ralt: '\u010d'
+ ralt+capslock, shift+ralt: '\u010c'
}
key V {
label: 'V'
base: 'v'
shift, capslock: 'V'
+ ralt: '\u01ef'
+ ralt+capslock, shift+ralt: '\u01ee'
}
key B {
label: 'B'
base: 'b'
shift, capslock: 'B'
+ ralt: '\u0292'
+ ralt+capslock, shift+ralt: '\u01b7'
}
key N {
label: 'N'
base: 'n'
shift, capslock: 'N'
+ ralt: '\u014b'
+ ralt+capslock, shift+ralt: '\u014a'
}
key M {
label: 'M'
base: 'm'
shift, capslock: 'M'
- ralt: '\u00b5'
+ ralt, ralt+capslock: '\u00b5'
}
key COMMA {
@@ -323,7 +359,7 @@
shift: ':'
}
-key MINUS {
+key SLASH {
label: '-'
base: '-'
shift: '_'
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm b/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm
index e42bd6c..8a4e9a5 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_swedish.kcm
@@ -13,13 +13,11 @@
# limitations under the License.
#
-# Swedish keyboard layout.
+# Swedish (Finnish) (EU based + Sami) keyboard layout.
#
type OVERLAY
-map key 12 SLASH
-map key 53 MINUS
map key 86 PLUS
### ROW 1
@@ -61,6 +59,7 @@
label: '5'
base: '5'
shift: '%'
+ ralt: '\u20ac'
}
key 6 {
@@ -97,7 +96,7 @@
ralt: '}'
}
-key SLASH {
+key MINUS {
label: '+'
base: '+'
shift: '?'
@@ -116,6 +115,8 @@
label: 'Q'
base: 'q'
shift, capslock: 'Q'
+ ralt: '\u00e2'
+ ralt+capslock, shift+ralt: '\u00c2'
}
key W {
@@ -129,6 +130,7 @@
base: 'e'
shift, capslock: 'E'
ralt: '\u20ac'
+ ralt+capslock: '\u20ac'
}
key R {
@@ -141,6 +143,8 @@
label: 'T'
base: 't'
shift, capslock: 'T'
+ ralt: '\u0167'
+ ralt+capslock, shift+ralt: '\u0166'
}
key Y {
@@ -159,12 +163,16 @@
label: 'I'
base: 'i'
shift, capslock: 'I'
+ ralt: '\u00ef'
+ ralt+capslock, shift+ralt: '\u00cf'
}
key O {
label: 'O'
base: 'o'
shift, capslock: 'O'
+ ralt: '\u00f5'
+ ralt+capslock, shift+ralt: '\u00d5'
}
key P {
@@ -192,36 +200,48 @@
label: 'A'
base: 'a'
shift, capslock: 'A'
+ ralt: '\u00e1'
+ ralt+capslock, shift+ralt: '\u00c1'
}
key S {
label: 'S'
base: 's'
shift, capslock: 'S'
+ ralt: '\u0161'
+ ralt+capslock, shift+ralt: '\u0160'
}
key D {
label: 'D'
base: 'd'
shift, capslock: 'D'
+ ralt: '\u0111'
+ ralt+capslock, shift+ralt: '\u0110'
}
key F {
label: 'F'
base: 'f'
shift, capslock: 'F'
+ ralt: '\u01e5'
+ ralt+capslock, shift+ralt: '\u01e4'
}
key G {
label: 'G'
base: 'g'
shift, capslock: 'G'
+ ralt: '\u01e7'
+ ralt+capslock, shift+ralt: '\u01e6'
}
key H {
label: 'H'
base: 'h'
shift, capslock: 'H'
+ ralt: '\u021f'
+ ralt+capslock, shift+ralt: '\u021e'
}
key J {
@@ -234,6 +254,8 @@
label: 'K'
base: 'k'
shift, capslock: 'K'
+ ralt: '\u01e9'
+ ralt+capslock, shift+ralt: '\u01e8'
}
key L {
@@ -246,12 +268,16 @@
label: '\u00d6'
base: '\u00f6'
shift, capslock: '\u00d6'
+ ralt: '\u00f8'
+ ralt+capslock, shift+ralt: '\u00d8'
}
key APOSTROPHE {
label: '\u00c4'
base: '\u00e4'
shift, capslock: '\u00c4'
+ ralt: '\u00e6'
+ ralt+capslock, shift+ralt: '\u00c6'
}
key BACKSLASH {
@@ -273,6 +299,8 @@
label: 'Z'
base: 'z'
shift, capslock: 'Z'
+ ralt: '\u017e'
+ ralt+capslock, shift+ralt: '\u017d'
}
key X {
@@ -285,31 +313,39 @@
label: 'C'
base: 'c'
shift, capslock: 'C'
+ ralt: '\u010d'
+ ralt+capslock, shift+ralt: '\u010c'
}
key V {
label: 'V'
base: 'v'
shift, capslock: 'V'
+ ralt: '\u01ef'
+ ralt+capslock, shift+ralt: '\u01ee'
}
key B {
label: 'B'
base: 'b'
shift, capslock: 'B'
+ ralt: '\u0292'
+ ralt+capslock, shift+ralt: '\u01b7'
}
key N {
label: 'N'
base: 'n'
shift, capslock: 'N'
+ ralt: '\u014b'
+ ralt+capslock, shift+ralt: '\u014a'
}
key M {
label: 'M'
base: 'm'
shift, capslock: 'M'
- ralt: '\u00b5'
+ ralt, ralt+capslock: '\u00b5'
}
key COMMA {
@@ -324,7 +360,7 @@
shift: ':'
}
-key MINUS {
+key SLASH {
label: '-'
base: '-'
shift: '_'
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 6239336..968961a 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -113,4 +113,7 @@
<!-- Spanish (Latin) keyboard layout label. [CHAR LIMIT=35] -->
<string name="keyboard_layout_spanish_latin">Spanish (Latin)</string>
+
+ <!-- Latvian keyboard layout label. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_latvian">Latvian</string>
</resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index dc1db0b..6f7253c 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -143,4 +143,8 @@
<keyboard-layout android:name="keyboard_layout_spanish_latin"
android:label="@string/keyboard_layout_spanish_latin"
android:keyboardLayout="@raw/keyboard_layout_spanish_latin" />
+
+ <keyboard-layout android:name="keyboard_layout_latvian"
+ android:label="@string/keyboard_layout_latvian"
+ android:keyboardLayout="@raw/keyboard_layout_latvian_qwerty" />
</keyboard-layouts>
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 0d943ed..f79819f 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -28,8 +28,6 @@
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
android:gravity="center_horizontal|top"
- android:layout_marginTop="48dp"
- android:layout_marginBottom="32dp"
android:contentDescription="@string/keyguard_accessibility_status">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index 5507e5f..5615ff7 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -23,4 +23,8 @@
<!-- Size of margin on the right of keyguard's status view -->
<dimen name="kg_status_line_font_right_margin">16dp</dimen>
+
+ <!-- Overload default clock widget parameters -->
+ <dimen name="widget_big_font_size">88dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-24dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index 25e86e1..a5e93dc 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -63,8 +63,9 @@
<dimen name="keyguard_muliuser_selector_margin">12dp</dimen>
<!-- Overload default clock widget parameters -->
- <dimen name="widget_label_font_size">16dp</dimen>
- <dimen name="widget_big_font_size">141dp</dimen>
+ <dimen name="widget_big_font_size">96dp</dimen>
+ <dimen name="widget_label_font_size">16sp</dimen>
+ <dimen name="bottom_text_spacing_digital">-24dp</dimen>
<!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
Should be 0 on devices with plenty of room (e.g. tablets) -->
diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml
index 30b979c..c487072 100644
--- a/packages/Keyguard/res/values-sw720dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw720dp/dimens.xml
@@ -61,7 +61,4 @@
<!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
<dimen name="keyguard_security_height">420dp</dimen>
- <!-- Default clock parameters -->
- <dimen name="widget_label_font_size">19dp</dimen>
-
</resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index c05f834..6224aed 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -155,10 +155,10 @@
<dimen name="eca_overlap">-10dip</dimen>
<!-- Default clock parameters -->
- <dimen name="bottom_text_spacing_digital">-8dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-18dp</dimen>
<dimen name="label_font_size">14dp</dimen>
- <dimen name="widget_label_font_size">14dp</dimen>
- <dimen name="widget_big_font_size">60dp</dimen>
+ <dimen name="widget_label_font_size">14sp</dimen>
+ <dimen name="widget_big_font_size">68dp</dimen>
<dimen name="big_font_size">120dp</dimen>
</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8425c48..94edc07 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -42,6 +42,8 @@
private boolean mIsBouncing;
private SecurityCallback mSecurityCallback;
+ private final KeyguardUpdateMonitor mUpdateMonitor;
+
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
public boolean dismiss(boolean authenticated);
@@ -62,6 +64,7 @@
super(context, attrs, defStyle);
mSecurityModel = new KeyguardSecurityModel(context);
mLockPatternUtils = new LockPatternUtils(context);
+ mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
}
public void setSecurityCallback(SecurityCallback callback) {
@@ -303,7 +306,9 @@
boolean showNextSecurityScreenOrFinish(boolean authenticated) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
boolean finish = false;
- if (SecurityMode.None == mCurrentSecuritySelection) {
+ if (mUpdateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
+ finish = true;
+ } else if (SecurityMode.None == mCurrentSecuritySelection) {
SecurityMode securityMode = mSecurityModel.getSecurityMode();
// Allow an alternate, such as biometric unlock
securityMode = mSecurityModel.getAlternateFor(securityMode);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 2d492db..5ef41c9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -83,8 +83,6 @@
} else if (simState == IccCardConstants.State.PUK_REQUIRED
&& mLockPatternUtils.isPukUnlockScreenEnable()) {
mode = SecurityMode.SimPuk;
- } else if (updateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
- mode = SecurityMode.None;
} else {
final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
switch (security) {
diff --git a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
index 1511911..7904927 100644
--- a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
@@ -22,6 +22,7 @@
<service
android:name=".SampleTrustAgent"
android:label="@string/app_name"
+ android:permission="android.permission.BIND_TRUST_AGENT"
android:exported="true">
<intent-filter>
<action android:name="android.service.trust.TrustAgentService" />
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 6f48fe8..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 5f2e95a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index e417a19..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index f325220..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index ee88a1b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 48606a8..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index d006f13..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index 867947b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index fe6dc52..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index aea75c1..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 58f67d0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index b794c9a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png
deleted file mode 100644
index fa23e85..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png
deleted file mode 100644
index aa8635c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png
deleted file mode 100644
index c36809b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 6158c01..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index f3e9da2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index a90aef9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 084799a..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png
deleted file mode 100644
index c37ba79..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index b05bf78..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 2f782cf..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 714f07e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index d59f0e92..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 8299301..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index e171d53..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 6fc556d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index a2342fc..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 1c847da2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index d0ab910..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 95df4d45..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 251fc30..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index b01b27f..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index 541e801..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index 0acf3a4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 25fc759..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index 9dfc3c6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index 82f4113..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 18b6029..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index b6ea14e..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 1e05a91..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index f4afa52..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png
deleted file mode 100644
index b0185a5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png
deleted file mode 100644
index 949ab10..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 4411097..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 79e4ff6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index ce965c2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index c798fd6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index ac5b09d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 945c606..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index 0a3f73e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index 398cbef..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 95cf67f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index efd8b9e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 662d062..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 18be9c0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png
deleted file mode 100644
index 7f7cb63..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png
deleted file mode 100644
index abdeb3b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 65b0204..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index dd16165..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index c5b7333..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index 1045e07..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index 7c20110..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 4621d18..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index a1ab61b..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index ea42a7f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 7f441c8..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index ce9bae2..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index aabf0aa..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 654c2a5..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png
deleted file mode 100644
index afe85b4..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png
deleted file mode 100644
index 5e5053f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_location_off_anim.xml b/packages/SystemUI/res/drawable/ic_location_off_anim.xml
deleted file mode 100644
index 864eda1..0000000
--- a/packages/SystemUI/res/drawable/ic_location_off_anim.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_location_on_anim.xml b/packages/SystemUI/res/drawable/ic_location_on_anim.xml
deleted file mode 100644
index 65a8afe..0000000
--- a/packages/SystemUI/res/drawable/ic_location_on_anim.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
- <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
similarity index 85%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
index ffe571f..9f0ec67 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
@@ -23,9 +23,13 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"
android:pathData="M10.2,9.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"
android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
similarity index 94%
rename from packages/SystemUI/res/drawable/ic_qs_airplane.xml
rename to packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
index ffe571f..95c20bb 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
@@ -23,9 +23,9 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M10.2,9.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
similarity index 96%
rename from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
rename to packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
index 22d0dcf..61a7777 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
similarity index 91%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
index 22d0dcf..7ac1cb9 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
@@ -23,6 +23,8 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"
android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
similarity index 96%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
index 22d0dcf..61a7777 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
index 2dfe183..2958848 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml b/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
deleted file mode 100644
index 70db2a9..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You 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.
- */
--->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="false">
- <item android:drawable="@drawable/ic_qs_cast_connecting_0" android:duration="500" />
- <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
- <item android:drawable="@drawable/ic_qs_cast_connecting_2" android:duration="500" />
- <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
similarity index 92%
copy from packages/SystemUI/res/drawable/ic_qs_cast.xml
copy to packages/SystemUI/res/drawable/ic_qs_cast_off.xml
index 6f2840b..130c639 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
@@ -23,6 +23,8 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"
android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
similarity index 97%
rename from packages/SystemUI/res/drawable/ic_qs_cast.xml
rename to packages/SystemUI/res/drawable/ic_qs_cast_on.xml
index 6f2840b..6c82b1c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_close.xml b/packages/SystemUI/res/drawable/ic_qs_close.xml
index c2c72c8..dd43e6c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_close.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_close.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M19.0,6.4l-1.3999996,-1.4000001 -5.6000004,5.6000004 -5.6,-5.6000004 -1.4000001,1.4000001 5.6000004,5.6 -5.6000004,5.6000004 1.4000001,1.3999996 5.6,-5.6000004 5.6000004,5.6000004 1.3999996,-1.3999996 -5.6000004,-5.6000004z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml b/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
similarity index 97%
rename from packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
rename to packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
index 7c92052..dc30a53 100644
--- a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml b/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml
deleted file mode 100644
index cf34ba6..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_qs_color_space_alpha"
- android:tint="@color/ic_qs_off" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml b/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml
deleted file mode 100644
index 1806688..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_qs_color_space_alpha"
- android:tint="@color/ic_qs_on" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
similarity index 93%
copy from packages/SystemUI/res/drawable/ic_qs_hotspot.xml
copy to packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
index 965e3c1..7a62212 100644
--- a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
@@ -23,6 +23,8 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"
android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
similarity index 97%
rename from packages/SystemUI/res/drawable/ic_qs_hotspot.xml
rename to packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
index 965e3c1..3ccdd81 100644
--- a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
deleted file mode 100644
index 9018a90..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_qs_inversion_alpha"
- android:tint="@color/ic_qs_off" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
deleted file mode 100644
index 9110201..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_qs_inversion_alpha"
- android:tint="@color/ic_qs_on" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_location.xml b/packages/SystemUI/res/drawable/ic_qs_location.xml
deleted file mode 100644
index e6e98a0..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FF000000"
- android:pathData="M12.0,2.0C8.1,2.0 5.0,5.1 5.0,9.0c0.0,5.2 7.0,13.0 7.0,13.0s7.0,-7.8 7.0,-13.0C19.0,5.1 15.9,2.0 12.0,2.0zM12.0,11.5c-1.4,0.0 -2.5,-1.1 -2.5,-2.5s1.1,-2.5 2.5,-2.5c1.4,0.0 2.5,1.1 2.5,2.5S13.4,11.5 12.0,11.5z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_01.xml b/packages/SystemUI/res/drawable/ic_qs_location_01.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_01.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_01.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_02.xml b/packages/SystemUI/res/drawable/ic_qs_location_02.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_02.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_02.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_03.xml b/packages/SystemUI/res/drawable/ic_qs_location_03.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_03.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_03.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_04.xml b/packages/SystemUI/res/drawable/ic_qs_location_04.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_04.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_04.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_05.xml b/packages/SystemUI/res/drawable/ic_qs_location_05.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_05.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_05.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_06.xml b/packages/SystemUI/res/drawable/ic_qs_location_06.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_06.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_06.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_07.xml b/packages/SystemUI/res/drawable/ic_qs_location_07.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_07.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_07.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_08.xml b/packages/SystemUI/res/drawable/ic_qs_location_08.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_08.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_08.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_09.xml b/packages/SystemUI/res/drawable/ic_qs_location_09.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_09.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_09.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_10.xml b/packages/SystemUI/res/drawable/ic_qs_location_10.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_10.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_10.xml
diff --git a/packages/SystemUI/res/drawable/ic_location_24_11.xml b/packages/SystemUI/res/drawable/ic_qs_location_11.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_location_24_11.xml
rename to packages/SystemUI/res/drawable/ic_qs_location_11.xml
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_off.xml b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
new file mode 100644
index 0000000..d28d347
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_on.xml b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
new file mode 100644
index 0000000..72512ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
index 8323e89..376cc28 100644
--- a/packages/SystemUI/res/drawable/ic_qs_minus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M7.0,11.0l0.0,2.0l10.0,0.0l0.0,-2.0L7.0,11.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
index 84cd72a..a315f7f 100644
--- a/packages/SystemUI/res/drawable/ic_qs_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M13.0,7.0l-2.0,0.0l0.0,4.0L7.0,11.0l0.0,2.0l4.0,0.0l0.0,4.0l2.0,0.0l0.0,-4.0l4.0,0.0l0.0,-2.0l-4.0,0.0L13.0,7.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
index fa6f20c..3a20c58 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
- android:pathData="M3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0L12.0,4.0L7.0,9.0L3.0,9.0zM16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0L14.0,16.0C15.5,15.3 16.5,13.8 16.5,12.0zM14.0,3.2l0.0,2.1c2.9,0.9 5.0,3.5 5.0,6.7s-2.1,5.8 -5.0,6.7l0.0,2.1c4.0,-0.9 7.0,-4.5 7.0,-8.8S18.0,4.1 14.0,3.2z"/>
+ android:fill="#FFFFFFFF"
+ android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
index 0665196..dd6be76 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
- android:pathData="M16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0l0.0,2.2l2.5,2.5C16.5,12.4 16.5,12.2 16.5,12.0zM19.0,12.0c0.0,0.9 -0.2,1.8 -0.5,2.6l1.5,1.5c0.7,-1.2 1.0,-2.7 1.0,-4.2c0.0,-4.3 -3.0,-7.9 -7.0,-8.8l0.0,2.1C16.9,6.2 19.0,8.8 19.0,12.0zM4.3,3.0L3.0,4.3L7.7,9.0L3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0l0.0,-6.7l4.3,4.3c-0.7,0.5 -1.4,0.9 -2.3,1.2l0.0,2.1c1.4,-0.3 2.6,-0.9 3.7,-1.8l2.0,2.0l1.3,-1.3l-9.0,-9.0L4.3,3.0zM12.0,4.0L9.9,6.1L12.0,8.2L12.0,4.0z"/>
+ android:fill="#FFFFFFFF"
+ android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
index 299a2ef..96d20e8 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
@@ -23,6 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
+ android:fill="#FFFFFFFF"
android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_01.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_01.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_01.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_01.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_02.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_02.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_02.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_02.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_03.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_03.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_03.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_03.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_04.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_04.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_04.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_04.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_05.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_05.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_05.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_05.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_06.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_06.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_06.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_06.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_07.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_07.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_07.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_07.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_08.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_08.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_08.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_08.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_09.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_09.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_09.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_09.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_10.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_10.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_10.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_10.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_11.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_11.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_11.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_11.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_12.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_12.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_12.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_12.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_13.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_13.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_13.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_13.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_14.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_14.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_14.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_14.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_15.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_15.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_15.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_15.xml
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_locked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_locked.xml
new file mode 100644
index 0000000..75e20f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_locked.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_qs_rotation_01" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_11" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_12" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_13" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_14" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_15" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
new file mode 100644
index 0000000..a1cedb9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_qs_rotation_15" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_14" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_13" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_12" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_11" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_qs_rotation_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/ic_qs_zen_off.xml
similarity index 66%
copy from packages/SystemUI/res/drawable/ic_qs_zen.xml
copy to packages/SystemUI/res/drawable/ic_qs_zen_off.xml
index 059c068..73886ec 100644
--- a/packages/SystemUI/res/drawable/ic_qs_zen.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_zen_off.xml
@@ -23,6 +23,8 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
- android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/>
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"
+ android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_zen_on.xml
similarity index 70%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/ic_qs_zen_on.xml
index ffe571f..8dff318 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_zen_on.xml
@@ -23,9 +23,6 @@
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
- android:pathData="M10.2,9.0"/>
- <path
- android:fill="#FF000000"
- android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
deleted file mode 100644
index e14a1ce..0000000
--- a/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
deleted file mode 100644
index 63b8c5f..0000000
--- a/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
- <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
similarity index 66%
rename from packages/SystemUI/res/drawable/ic_qs_zen.xml
rename to packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
index 059c068..5efd8ec 100644
--- a/packages/SystemUI/res/drawable/ic_qs_zen.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -15,14 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="19dp"
+ android:height="19dp"/>
<viewport
android:viewportWidth="24.0"
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
- android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/>
+ android:fill="#FFFFFFFF"
+ android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
similarity index 62%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index ffe571f..e1d63c3 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -15,17 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="20dp"
+ android:height="20dp"/>
<viewport
android:viewportWidth="24.0"
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
- android:pathData="M10.2,9.0"/>
- <path
- android:fill="#FF000000"
- android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+ android:fill="#FFFFFFFF"
+ android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
similarity index 65%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
index ffe571f..afab88f 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
@@ -15,17 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="19dp"
+ android:height="19dp"/>
<viewport
android:viewportWidth="24.0"
android:viewportHeight="24.0"/>
<path
- android:fill="#FF000000"
- android:pathData="M10.2,9.0"/>
- <path
- android:fill="#FF000000"
- android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
</vector>
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
index 2df6d43..b73874a 100644
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
@@ -19,8 +19,9 @@
android:layout_height="match_parent"
android:background="@color/system_secondary_color" >
- <com.android.systemui.qs.QSImageView
+ <ImageView
android:id="@android:id/button1"
+ android:src="@drawable/ic_qs_close"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_alignParentStart="true"
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
index a5c8903..7e02bee 100644
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
@@ -38,8 +38,9 @@
android:maxLines="1"
android:text="@string/accessibility_back" />
- <com.android.systemui.qs.QSImageView
+ <ImageView
android:id="@android:id/button1"
+ android:src="@drawable/ic_qs_plus"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_alignParentEnd="true"
@@ -47,8 +48,9 @@
android:padding="@dimen/quick_settings_panel_padding"
android:paddingRight="0px" />
- <com.android.systemui.qs.QSImageView
+ <ImageView
android:id="@android:id/button2"
+ android:src="@drawable/ic_qs_minus"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_alignParentEnd="true"
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index bda6431..a68ad2f 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -16,7 +16,8 @@
<com.android.systemui.recents.views.TaskView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:focusable="true">
<com.android.systemui.recents.views.TaskThumbnailView
android:id="@+id/task_view_thumbnail"
android:layout_width="match_parent"
@@ -69,7 +70,7 @@
android:layout_height="@dimen/recents_task_view_application_icon_size"
android:layout_gravity="center_vertical|end"
android:padding="23dp"
- android:src="@drawable/recents_dismiss_dark" />
+ android:src="@drawable/recents_dismiss_light" />
</com.android.systemui.recents.views.TaskBarView>
</com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 585658e..eaa2558 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -61,11 +61,6 @@
android:src="@drawable/stat_notify_more"
android:visibility="gone"
/>
- <com.android.systemui.statusbar.StatusBarIconView android:id="@+id/modeIcon"
- android:layout_width="@dimen/status_bar_icon_size"
- android:layout_height="match_parent"
- android:visibility="gone"
- />
<com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 30eedee..8348e9b 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -18,7 +18,7 @@
<com.android.systemui.statusbar.NotificationOverflowContainer
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="40dp"
+ android:layout_height="@dimen/notification_summary_height"
android:focusable="true"
android:clickable="true"
>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
new file mode 100644
index 0000000..ff8800c
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
@@ -0,0 +1,65 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Extends FrameLayout -->
+<com.android.systemui.statusbar.SpeedBumpView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:clickable="true"
+ android:visibility="gone"
+ >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/speed_bump_height_collapsed"
+ android:layout_gravity="top"
+ android:orientation="horizontal">
+ <View
+ android:id="@+id/speedbump_line_left"
+ android:layout_width="0dp"
+ android:layout_height="1dp"
+ android:layout_weight="1"
+ android:background="#6fdddddd"
+ android:layout_gravity="center_vertical"/>
+ <com.android.systemui.statusbar.SpeedBumpDotsLayout
+ android:id="@+id/speed_bump_dots_layout"
+ android:layout_width="34dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"/>
+ <View
+ android:id="@+id/speedbump_line_right"
+ android:layout_width="0dp"
+ android:layout_height="1dp"
+ android:layout_weight="1"
+ android:background="#6fdddddd"
+ android:layout_gravity="center_vertical"/>
+ </LinearLayout>
+ <TextView
+ android:id="@+id/speed_bump_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal"
+ android:fontFamily="sans-serif-condensed"
+ android:textSize="15sp"
+ android:singleLine="true"
+ android:textColor="#eeeeee"
+ android:visibility="invisible"
+ android:text="@string/speed_bump_explanation"
+ android:paddingTop="4dp" />
+</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/values-sw600dp-land/values-land-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
similarity index 85%
rename from packages/SystemUI/res/values-sw600dp-land/values-land-sw600dp/dimens.xml
rename to packages/SystemUI/res/values-sw600dp-land/dimens.xml
index e440de1..b510fef 100644
--- a/packages/SystemUI/res/values-sw600dp-land/values-land-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -18,4 +18,7 @@
<resources>
<!-- Recent Applications parameters -->
<dimen name="status_bar_recents_app_label_width">190dip</dimen>
+
+ <fraction name="keyguard_clock_y_fraction_max">37%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">14%</fraction>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 7372181..22815f3 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -48,4 +48,15 @@
<!-- Width of the zen mode interstitial dialog. -->
<dimen name="zen_mode_dialog_width">384dp</dimen>
+
+ <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+ max value is used when no notifications are displaying, and the min value is when the
+ highest possible number of notifications are showing. -->
+ <fraction name="keyguard_clock_y_fraction_max">34%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">25%</fraction>
+
+ <!-- The margin between the clock and the notifications on Keyguard. See
+ keyguard_clock_height_fraction_* for the difference between min and max.-->
+ <dimen name="keyguard_clock_notifications_margin_min">32dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_max">32dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..2532dd6
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<resources>
+ <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+ min value is used when no notifications are displaying, and the max value is when the
+ highest possible number of notifications are showing. -->
+ <fraction name="keyguard_clock_y_fraction_max">35%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">20%</fraction>
+</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index 7cf711a..d8bb8d7d 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -35,5 +35,9 @@
<!-- Transposes the search bar layout in landscape -->
<bool name="recents_transpose_search_layout_with_orientation">false</bool>
+
+ <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
+ card. -->
+ <integer name="keyguard_max_notification_count">5</integer>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index a1c5b66..7695b12 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -65,5 +65,11 @@
<!-- Where to place the app icon over the thumbnail -->
<dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
<dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
+
+ <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+ max value is used when no notifications are displaying, and the min value is when the
+ highest possible number of notifications are showing. -->
+ <fraction name="keyguard_clock_y_fraction_max">35%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">25%</fraction>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9582b21..77b4843 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -41,8 +41,6 @@
<color name="system_secondary_color">#ff384248</color>
<color name="system_accent_color">#ff7fcac3</color>
<color name="system_error_color">#fff0592b</color>
- <color name="quick_settings_tile_icon_enabled">#ffffffff</color>
- <color name="quick_settings_tile_icon_disabled">#ffcccccc</color>
<color name="quick_settings_tile_divider">#ff888888</color>
<color name="quick_settings_tile_text">#FFFFFFFF</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
@@ -58,6 +56,18 @@
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff666666</color>
+ <!-- The color of the red speed bump dot -->
+ <color name="speed_bump_dot_red">#ffd50000</color>
+
+ <!-- The color of the blue speed bump dot -->
+ <color name="speed_bump_dot_blue">#ff2962ff</color>
+
+ <!-- The color of the yellow speed bump dot -->
+ <color name="speed_bump_dot_yellow">#ffffd600</color>
+
+ <!-- The color of the green speed bump dot -->
+ <color name="speed_bump_dot_green">#ff00c853</color>
+
<!-- The default recents task bar background color. -->
<color name="recents_task_bar_default_background_color">#e6444444</color>
<!-- The default recents task bar text color. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79612e0..29955dd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -82,6 +82,9 @@
<!-- Height of a medium notification in the status bar -->
<dimen name="notification_mid_height">128dp</dimen>
+ <!-- Height of a the summary ("more card") notification on keyguard. -->
+ <dimen name="notification_summary_height">40dp</dimen>
+
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">18dip</dimen>
@@ -260,6 +263,15 @@
<!-- The padding between the individual notification cards. -->
<dimen name="notification_padding">4dp</dimen>
+ <!-- The height of the collapsed speed bump view. -->
+ <dimen name="speed_bump_height_collapsed">24dp</dimen>
+
+ <!-- The padding inset the explanation text needs compared to the collapsed height -->
+ <dimen name="speed_bump_text_padding_inset">10dp</dimen>
+
+ <!-- The height of the speed bump dots. -->
+ <dimen name="speed_bump_dots_height">5dp</dimen>
+
<!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
<dimen name="collapsed_stack_height">94dp</dimen>
@@ -272,7 +284,6 @@
<dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
<dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
<dimen name="quick_settings_panel_padding">16dp</dimen>
- <dimen name="quick_settings_tile_icon_outline">2dp</dimen>
<dimen name="quick_settings_tile_text_size">12sp</dimen>
<dimen name="quick_settings_tile_divider_height">1dp</dimen>
@@ -280,4 +291,16 @@
<!-- Minimum distance the user has to drag down to go to the full shade. -->
<dimen name="keyguard_drag_down_min_distance">100dp</dimen>
+
+ <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+ max value is used when no notifications are displaying, and the min value is when the
+ highest possible number of notifications are showing. -->
+ <fraction name="keyguard_clock_y_fraction_max">29.5%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">18%</fraction>
+
+ <!-- The margin between the clock and the notifications on Keyguard. See
+ keyguard_clock_height_fraction_* for the difference between min and max.-->
+ <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a50a0ac..f5bc353 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -553,9 +553,14 @@
<item quantity="other">%d more</item>
</plurals>
+ <!-- An explanation for the visual speed bump in the notifications, which will appear when you click on it. [CHAR LIMIT=50] -->
+ <string name="speed_bump_explanation">Less urgent notifications below</string>
+
<!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
<string name="notification_tap_again">Tap again to open</string>
<!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to unlock</string>
+
+ <string name="bugreport_tile_extended" translatable="false">%s\n%s (%s)</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9536b12..19888a8 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -193,4 +193,9 @@
</style>
<style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
+
+ <style name="QSBorderless.Tiny">
+ <item name="android:minHeight">12dip</item>
+ <item name="android:minWidth">12dip</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 323905f..105f70e 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -20,11 +20,9 @@
import android.view.View;
public interface RecentsComponent {
+ void showRecents(boolean triggeredFromAltTab, View statusBarView);
+ void hideRecents();
void toggleRecents(Display display, int layoutDirection, View statusBarView);
-
- void preloadRecentTasksList();
-
- void cancelPreloadingRecentTasksList();
-
- void closeRecents();
+ void preloadRecents();
+ void cancelPreloadingRecents();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
deleted file mode 100644
index 05c8ee3..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
+++ /dev/null
@@ -1,79 +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.systemui.qs;
-
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-
-/** Canvas that forwards calls to another canvas. Can be subclassed to transform drawing calls.
- * Temporary solution to runtime modification of a single drawable shape into two
- * enabled & disabled versions. See QSImageView. **/
-public class FilterCanvas extends Canvas {
- private final Canvas mCanvas;
-
- public FilterCanvas(Canvas c) {
- mCanvas = c;
- }
-
- @Override
- public void drawPath(Path path, Paint paint) {
- mCanvas.drawPath(path, paint);
- }
-
- @Override
- public int getSaveCount() {
- return mCanvas.getSaveCount();
- }
-
- @Override
- public int save() {
- return mCanvas.save();
- }
-
- @Override
- public void translate(float dx, float dy) {
- mCanvas.translate(dx, dy);
- }
-
- @Override
- public boolean clipRect(int left, int top, int right, int bottom) {
- return mCanvas.clipRect(left, top, right, bottom);
- }
-
- @Override
- public boolean clipRect(Rect rect) {
- return mCanvas.clipRect(rect);
- }
-
- @Override
- public void concat(Matrix matrix) {
- mCanvas.concat(matrix);
- }
-
- @Override
- public void restoreToCount(int saveCount) {
- mCanvas.restoreToCount(saveCount);
- }
-
- @Override
- public void drawRect(Rect r, Paint paint) {
- mCanvas.drawRect(r, paint);
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
index 1e15b9f..c169df0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
@@ -21,10 +21,10 @@
import android.os.Handler;
import android.provider.Settings.Global;
-import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.Listenable;
/** Helper for managing a global setting. **/
-public abstract class GlobalSetting extends ContentObserver implements Disposable {
+public abstract class GlobalSetting extends ContentObserver implements Listenable {
private final Context mContext;
private final String mSettingName;
@@ -34,8 +34,6 @@
super(handler);
mContext = context;
mSettingName = settingName;
- mContext.getContentResolver().registerContentObserver(
- Global.getUriFor(mSettingName), false, this);
}
public int getValue() {
@@ -47,8 +45,13 @@
}
@Override
- public void dispose() {
- mContext.getContentResolver().unregisterContentObserver(this);
+ public void setListening(boolean listening) {
+ if (listening) {
+ mContext.getContentResolver().registerContentObserver(
+ Global.getUriFor(mSettingName), false, this);
+ } else {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
deleted file mode 100644
index ed67560..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
+++ /dev/null
@@ -1,102 +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.systemui.qs;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Path;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.VectorDrawable;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-
-/** ImageView that performs runtime modification of vector drawables (using FilterCanvas). **/
-public class QSImageView extends ImageView {
-
- private final int mOutlineWidth;
- private final int mColorEnabled;
- private final int mColorDisabled;
- private FilterCanvas mFilterCanvas;
- private Canvas mCanvas;
- private boolean mEnabledVersion = true;
- private boolean mFilter;
-
- public QSImageView(Context context) {
- this(context, null);
- }
-
- public QSImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- final Resources res = context.getResources();
- mOutlineWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tile_icon_outline);
- mColorEnabled = res.getColor(R.color.quick_settings_tile_icon_enabled);
- mColorDisabled = res.getColor(R.color.quick_settings_tile_icon_disabled);
- }
-
- public void setEnabledVersion(boolean enabledVersion) {
- mEnabledVersion = enabledVersion;
- invalidate();
- }
-
- @Override
- public void setImageDrawable(Drawable drawable) {
- mFilter = drawable instanceof VectorDrawable;
- super.setImageDrawable(drawable);
- }
-
- @Override
- public void setImageResource(int resId) {
- setImageDrawable(mContext.getDrawable(resId));
- }
-
- @Override
- public void draw(Canvas canvas) {
- if (mFilter) {
- if (canvas != mCanvas) {
- mCanvas = canvas;
- mFilterCanvas = new QSFilterCanvas(canvas);
- }
- super.draw(mFilterCanvas);
- } else {
- super.draw(canvas);
- }
- }
-
- private class QSFilterCanvas extends FilterCanvas {
- public QSFilterCanvas(Canvas c) {
- super(c);
- }
-
- @Override
- public void drawPath(Path path, Paint paint) {
- if (mEnabledVersion) {
- paint.setColor(mColorEnabled);
- } else {
- paint.setStyle(Style.STROKE);
- paint.setStrokeJoin(Paint.Join.ROUND);
- paint.setColor(mColorDisabled);
- paint.setStrokeWidth(mOutlineWidth);
- }
- super.drawPath(path, paint);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index afb5483..6176eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -80,7 +80,10 @@
showDetail(false /*show*/, mDetailRecord);
}
for (TileRecord r : mRecords) {
- r.tile.setShown(expanded);
+ r.tile.setListening(expanded);
+ if (expanded) {
+ r.tile.refreshState();
+ }
}
}
@@ -125,6 +128,7 @@
}
};
r.tileView.init(click, clickSecondary);
+ r.tile.refreshState();
mRecords.add(r);
addView(r.tileView);
@@ -156,24 +160,29 @@
mCellHeight = (int)(mCellWidth / TILE_ASPECT);
mLargeCellWidth = (int)(mCellWidth * LARGE_TILE_FACTOR);
mLargeCellHeight = (int)(mCellHeight * LARGE_TILE_FACTOR);
- int r = 0;
- int c = 0;
+ int r = -1;
+ int c = -1;
int rows = 0;
+ boolean rowIsDual = false;
for (TileRecord record : mRecords) {
if (record.tileView.getVisibility() == GONE) continue;
+ // wrap to next column if we've reached the max # of columns
+ // also don't allow dual + single tiles on the same row
+ if (r == -1 || c == (mColumns - 1) || rowIsDual != record.tile.supportsDualTargets()) {
+ r++;
+ c = 0;
+ rowIsDual = record.tile.supportsDualTargets();
+ } else {
+ c++;
+ }
record.row = r;
record.col = c;
rows = r + 1;
- c++;
- if (c == mColumns /*end of normal column*/ || r == 0 && c == 2 /*end of 1st column*/) {
- c = 0;
- r++;
- }
}
for (TileRecord record : mRecords) {
if (record.tileView.getVisibility() == GONE) continue;
- record.tileView.setDual(record.row == 0);
+ record.tileView.setDual(record.tile.supportsDualTargets());
final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
record.tileView.measure(exactly(cw), exactly(ch));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 05f308d..835a5c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -30,7 +29,7 @@
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.Listenable;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -47,8 +46,10 @@
* handleUpdateState. Callbacks affecting state should use refreshState to trigger another
* state update pass on tile looper.
*/
-public abstract class QSTile<TState extends State> implements Disposable {
- private final String TAG = "QSTile." + getClass().getSimpleName();
+public abstract class QSTile<TState extends State> implements Listenable {
+ protected final String TAG = "QSTile." + getClass().getSimpleName();
+ protected static final boolean DEBUG = false;
+ public static final int FEEDBACK_START_DELAY = 400;
protected final Host mHost;
protected final Context mContext;
@@ -69,6 +70,10 @@
mHandler = new H(host.getLooper());
}
+ public boolean supportsDualTargets() {
+ return false;
+ }
+
public Host getHost() {
return mHost;
}
@@ -111,10 +116,6 @@
mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
}
- public void setShown(boolean shown) {
- mHandler.obtainMessage(H.SHOWN, shown ? 1 : 0, 0).sendToTarget();
- }
-
// call only on tile worker looper
private void handleSetCallback(Callback callback) {
@@ -126,10 +127,6 @@
// optional
}
- protected void handleShown(boolean shown) {
- // optional, discouraged
- }
-
protected void handleRefreshState(Object arg) {
handleUpdateState(mTmpState, arg);
final boolean changed = mTmpState.copyTo(mState);
@@ -161,7 +158,6 @@
private static final int REFRESH_STATE = 4;
private static final int SHOW_DETAIL = 5;
private static final int USER_SWITCH = 6;
- private static final int SHOWN = 7;
private H(Looper looper) {
super(looper);
@@ -189,9 +185,6 @@
} else if (msg.what == USER_SWITCH) {
name = "handleUserSwitch";
handleUserSwitch(msg.arg1);
- } else if (msg.what == SHOWN) {
- name = "handleShown";
- handleShown(msg.arg1 != 0);
}
} catch (Throwable t) {
final String error = "Error in " + name;
@@ -212,7 +205,6 @@
void collapsePanels();
Looper getLooper();
Context getContext();
- VectorDrawable getVectorDrawable(int resId);
BluetoothController getBluetoothController();
LocationController getLocationController();
RotationLockController getRotationLockController();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 17a95fb..4cfb636 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -25,9 +25,11 @@
import android.os.Looper;
import android.os.Message;
import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TextView;
@@ -43,9 +45,9 @@
protected final Context mContext;
private final View mIcon;
private final View mDivider;
- private final TextView mLabel;
private final H mHandler = new H();
+ private TextView mLabel;
private boolean mDual;
private OnClickListener mClickPrimary;
private OnClickListener mClickSecondary;
@@ -55,14 +57,7 @@
mContext = context;
final Resources res = context.getResources();
- mLabel = new TextView(mContext);
- mLabel.setId(android.R.id.title);
- mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text));
- mLabel.setGravity(Gravity.CENTER);
- mLabel.setTypeface(CONDENSED);
- mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size));
- addView(mLabel);
+ recreateLabel();
setClipChildren(false);
mIcon = createIcon();
@@ -78,8 +73,33 @@
setBackground(getSelectableBackground());
}
+ private void recreateLabel() {
+ CharSequence labelText = null;
+ if (mLabel != null) {
+ labelText = mLabel.getText();
+ removeView(mLabel);
+ }
+ final Resources res = mContext.getResources();
+ mLabel = new TextView(mDual ? new ContextThemeWrapper(mContext, R.style.QSBorderless_Tiny)
+ : mContext);
+ mLabel.setId(android.R.id.title);
+ mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text));
+ mLabel.setGravity(Gravity.CENTER);
+ mLabel.setTypeface(CONDENSED);
+ mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size));
+ if (labelText != null) {
+ mLabel.setText(labelText);
+ }
+ addView(mLabel);
+ }
+
public void setDual(boolean dual) {
+ final boolean changed = dual != mDual;
mDual = dual;
+ if (changed) {
+ recreateLabel();
+ }
if (mDual) {
setOnClickListener(mClickPrimary);
mLabel.setClickable(true);
@@ -98,7 +118,7 @@
}
protected View createIcon() {
- QSImageView icon = new QSImageView(mContext);
+ final ImageView icon = new ImageView(mContext);
icon.setId(android.R.id.icon);
icon.setScaleType(ScaleType.CENTER_INSIDE);
return icon;
@@ -120,9 +140,10 @@
final int iconSpec = exactly((int)mLabel.getTextSize() * 2);
mIcon.measure(iconSpec, iconSpec);
mLabel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
- mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2));
if (mDual) {
mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
+ } else {
+ mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2));
}
setMeasuredDimension(w, h);
}
@@ -156,15 +177,12 @@
}
protected void handleStateChanged(QSTile.State state) {
- if (mIcon instanceof QSImageView) {
- QSImageView qsiv = (QSImageView) mIcon;
+ if (mIcon instanceof ImageView) {
+ ImageView iv = (ImageView) mIcon;
if (state.icon != null) {
- qsiv.setImageDrawable(state.icon);
+ iv.setImageDrawable(state.icon);
} else if (state.iconId > 0) {
- qsiv.setImageResource(state.iconId);
- }
- if (state.icon != null && state instanceof QSTile.BooleanState) {
- qsiv.setEnabledVersion(((QSTile.BooleanState)state).value);
+ iv.setImageResource(state.iconId);
}
}
mLabel.setText(state.label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
index 4debaa9..3ed3d30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -21,10 +21,10 @@
import android.os.Handler;
import android.provider.Settings.Secure;
-import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.Listenable;
/** Helper for managing a secure setting. **/
-public abstract class SecureSetting extends ContentObserver implements Disposable {
+public abstract class SecureSetting extends ContentObserver implements Listenable {
private final Context mContext;
private final String mSettingName;
@@ -38,8 +38,7 @@
}
public void rebindForCurrentUser() {
- mContext.getContentResolver().registerContentObserver(
- Secure.getUriFor(mSettingName), false, this);
+ setListening(true);
}
public int getValue() {
@@ -51,8 +50,13 @@
}
@Override
- public void dispose() {
- mContext.getContentResolver().unregisterContentObserver(this);
+ public void setListening(boolean listening) {
+ if (listening) {
+ mContext.getContentResolver().registerContentObserver(
+ Secure.getUriFor(mSettingName), false, this);
+ } else {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 5fe8422..c0f9bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -39,11 +39,6 @@
handleRefreshState(value);
}
};
-
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- mContext.registerReceiver(mReceiver, filter);
- refreshState();
}
@Override
@@ -70,7 +65,6 @@
state.value = airplaneMode;
state.visible = true;
state.label = mContext.getString(R.string.quick_settings_airplane_mode_label);
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_airplane);
if (airplaneMode) {
state.iconId = R.drawable.ic_qs_airplane_on;
state.contentDescription = mContext.getString(
@@ -84,9 +78,15 @@
}
}
- public void dispose() {
- mSetting.dispose();
- mContext.unregisterReceiver(mReceiver);
+ public void setListening(boolean listening) {
+ if (listening) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+ } else {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ mSetting.setListening(listening);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 60a6047..7335ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -33,7 +33,11 @@
public BluetoothTile(Host host) {
super(host);
mController = host.getBluetoothController();
- mController.addStateChangedCallback(mCallback);
+ }
+
+ @Override
+ public boolean supportsDualTargets() {
+ return true;
}
@Override
@@ -42,8 +46,12 @@
}
@Override
- public void dispose() {
- mController.removeStateChangedCallback(mCallback);
+ public void setListening(boolean listening) {
+ if (listening) {
+ mController.addStateChangedCallback(mCallback);
+ } else {
+ mController.removeStateChangedCallback(mCallback);
+ }
}
@Override
@@ -64,14 +72,13 @@
final boolean connected = mController.isBluetoothConnected();
state.visible = supported;
state.value = enabled;
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bluetooth);
final String stateContentDescription;
if (enabled) {
if (connected) {
- state.iconId = R.drawable.ic_qs_bluetooth_on;
+ state.iconId = R.drawable.ic_qs_bluetooth_connected;
stateContentDescription = mContext.getString(R.string.accessibility_desc_connected);
} else {
- state.iconId = R.drawable.ic_qs_bluetooth_not_connected;
+ state.iconId = R.drawable.ic_qs_bluetooth_on;
stateContentDescription = mContext.getString(R.string.accessibility_desc_on);
}
state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
index 0e9b9a7..fa41837 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -21,6 +21,7 @@
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
+import android.os.Build;
import android.os.RemoteException;
import android.provider.Settings.Global;
import android.view.WindowManager;
@@ -51,22 +52,30 @@
}
@Override
- public void dispose() {
- mSetting.dispose();
+ public void setListening(boolean listening) {
+ mSetting.setListening(listening);
}
@Override
protected void handleClick() {
- mHost.collapsePanels();
- mUiHandler.post(mShowDialog);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mHost.collapsePanels();
+ mUiHandler.post(mShowDialog);
+ }
+ }, FEEDBACK_START_DELAY);
}
@Override
protected void handleUpdateState(State state, Object pushArg) {
state.visible = mSetting.getValue() != 0;
- state.iconId = com.android.internal.R.drawable.stat_sys_adb;
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bugreport);
- state.label = mContext.getString(com.android.internal.R.string.bugreport_title);
+ state.iconId = R.drawable.ic_qs_bugreport;
+ state.label = mContext.getString(
+ R.string.bugreport_tile_extended,
+ mContext.getString(com.android.internal.R.string.bugreport_title),
+ Build.VERSION.RELEASE,
+ Build.ID);
}
private final Runnable mShowDialog = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index a3eaa2c..907c77e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -35,14 +35,9 @@
private final CastController mController;
- private boolean mShown;
-
public CastTile(Host host) {
super(host);
mController = host.getCastController();
- if (mController != null) {
- mController.addCallback(mCallback);
- }
}
@Override
@@ -51,9 +46,14 @@
}
@Override
- public void dispose() {
+ public void setListening(boolean listening) {
if (mController == null) return;
- mController.removeCallback(mCallback);
+ if (listening) {
+ mController.addCallback(mCallback);
+ } else {
+ mController.removeCallback(mCallback);
+ }
+ mController.setDiscovering(listening);
}
@Override
@@ -64,17 +64,13 @@
}
@Override
- protected void handleShown(boolean shown) {
- if (mShown == shown) return;
- if (mController == null) return;
- mShown = shown;
- mController.setDiscovering(mShown);
- }
-
- @Override
protected void handleClick() {
- mHost.collapsePanels();
- mUiHandler.post(mShowDialog);
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mHost.collapsePanels();
+ mUiHandler.post(mShowDialog);
+ }
+ }, FEEDBACK_START_DELAY);
}
@Override
@@ -82,13 +78,13 @@
state.visible = true;
state.label = mContext
.getString(R.string.quick_settings_remote_display_no_connection_label);
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_cast);
if (arg instanceof CallbackInfo) {
final CallbackInfo cb = (CallbackInfo) arg;
if (cb.connectedRouteName != null) {
state.value = !cb.connecting;
}
}
+ state.iconId = state.value ? R.drawable.ic_qs_cast_on : R.drawable.ic_qs_cast_off;
}
private static class CallbackInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 86a4e79..182a0ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -38,7 +38,6 @@
public CellularTile(Host host) {
super(host);
mController = host.getNetworkController();
- mController.addNetworkSignalChangedCallback(mCallback);
}
@Override
@@ -47,8 +46,12 @@
}
@Override
- public void dispose() {
- mController.removeNetworkSignalChangedCallback(mCallback);
+ public void setListening(boolean listening) {
+ if (listening) {
+ mController.addNetworkSignalChangedCallback(mCallback);
+ } else {
+ mController.removeNetworkSignalChangedCallback(mCallback);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 66740af..5301362 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -39,8 +39,6 @@
handleRefreshState(value);
}
};
-
- refreshState();
}
@Override
@@ -49,8 +47,8 @@
}
@Override
- public void dispose() {
- mSetting.dispose();
+ public void setListening(boolean listening) {
+ mSetting.setListening(listening);
}
@Override
@@ -73,6 +71,6 @@
state.visible = mVisible;
state.value = enabled;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_invert_colors);
+ state.iconId = R.drawable.ic_qs_color_inversion;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 1a67afc..f2ba558 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -42,7 +42,7 @@
}
@Override
- public void dispose() {
+ public void setListening(boolean listening) {
}
@@ -55,6 +55,6 @@
protected void handleUpdateState(State state, Object arg) {
state.visible = mController != null;
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_hotspot);
+ state.iconId = R.drawable.ic_qs_hotspot_off;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 176e05c..c5ad9e6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -31,7 +31,6 @@
public LocationTile(Host host) {
super(host);
mController = host.getLocationController();
- mController.addSettingsChangedCallback(mCallback);
}
@Override
@@ -39,8 +38,13 @@
return new BooleanState();
}
- public void dispose() {
- mController.removeSettingsChangedCallback(mCallback);
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mController.addSettingsChangedCallback(mCallback);
+ } else {
+ mController.removeSettingsChangedCallback(mCallback);
+ }
}
@Override
@@ -61,8 +65,8 @@
if (state.value != locationEnabled) {
state.value = locationEnabled;
final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(locationEnabled
- ? R.drawable.ic_location_on_anim
- : R.drawable.ic_location_off_anim);
+ ? R.drawable.ic_qs_location_on
+ : R.drawable.ic_qs_location_off);
state.icon = d;
mUiHandler.post(new Runnable() {
@Override
@@ -71,15 +75,14 @@
}
});
}
- //state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
if (locationEnabled) {
- if (state.icon == null) state.iconId = R.drawable.ic_location_24_01;
+ if (state.icon == null) state.iconId = R.drawable.ic_qs_location_01;
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
mContext.getString(R.string.accessibility_desc_on));
} else {
- if (state.icon == null) state.iconId = R.drawable.ic_location_24_11;
+ if (state.icon == null) state.iconId = R.drawable.ic_qs_location_11;
state.label = mContext.getString(R.string.quick_settings_location_off_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
index 36a579c..c5e9b52 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
@@ -33,8 +33,6 @@
public RingerModeTile(Host host) {
super(host);
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
- mContext.registerReceiver(mReceiver, filter);
}
@Override
@@ -43,8 +41,13 @@
}
@Override
- public void dispose() {
- mContext.unregisterReceiver(mReceiver);
+ public void setListening(boolean listening) {
+ if (listening) {
+ final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ mContext.registerReceiver(mReceiver, filter);
+ } else {
+ mContext.unregisterReceiver(mReceiver);
+ }
}
@Override
@@ -64,13 +67,13 @@
state.visible = true;
state.value = ringerMode;
if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_vibrate);
+ state.iconId = R.drawable.ic_qs_ringer_vibrate;
state.label = "Vibrate";
} else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_silent);
+ state.iconId = R.drawable.ic_qs_ringer_silent;
state.label = "Silent";
} else {
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_audible);
+ state.iconId = R.drawable.ic_qs_ringer_audible;
state.label = "Audible";
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index d075299..1b0967b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -33,8 +33,6 @@
public RotationLockTile(Host host) {
super(host);
mController = host.getRotationLockController();
- if (mController == null) return;
- mController.addRotationLockControllerCallback(mCallback);
}
@Override
@@ -42,9 +40,13 @@
return new BooleanState();
}
- public void dispose() {
+ public void setListening(boolean listening) {
if (mController == null) return;
- mController.removeRotationLockControllerCallback(mCallback);
+ if (listening) {
+ mController.addRotationLockControllerCallback(mCallback);
+ } else {
+ mController.removeRotationLockControllerCallback(mCallback);
+ }
}
@Override
@@ -61,8 +63,8 @@
if (state.value != rotationLocked) {
state.value = rotationLocked;
final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(rotationLocked
- ? R.drawable.ic_rotate_locked_anim
- : R.drawable.ic_rotate_unlocked_anim);
+ ? R.drawable.ic_qs_rotation_locked
+ : R.drawable.ic_qs_rotation_unlocked);
state.icon = d;
mUiHandler.post(new Runnable() {
@Override
@@ -80,12 +82,12 @@
: R.string.quick_settings_rotation_locked_label;
state.label = mContext.getString(label);
if (state.icon == null) {
- state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_15);
+ state.icon = mContext.getDrawable(R.drawable.ic_qs_rotation_15);
}
} else {
state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
if (state.icon == null) {
- state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_01);
+ state.icon = mContext.getDrawable(R.drawable.ic_qs_rotation_01);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index e08a6fa..ef7fb89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.content.res.Resources;
import android.provider.Settings;
+import android.util.Log;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -37,7 +38,11 @@
public WifiTile(Host host) {
super(host);
mController = host.getNetworkController();
- mController.addNetworkSignalChangedCallback(mCallback);
+ }
+
+ @Override
+ public boolean supportsDualTargets() {
+ return true;
}
@Override
@@ -46,8 +51,12 @@
}
@Override
- public void dispose() {
- mController.removeNetworkSignalChangedCallback(mCallback);
+ public void setListening(boolean listening) {
+ if (listening) {
+ mController.addNetworkSignalChangedCallback(mCallback);
+ } else {
+ mController.removeNetworkSignalChangedCallback(mCallback);
+ }
}
@Override
@@ -67,8 +76,9 @@
@Override
protected void handleUpdateState(SignalState state, Object arg) {
- if (arg == null) return;
state.visible = true;
+ if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
+ if (arg == null) return;
CallbackInfo cb = (CallbackInfo) arg;
boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
@@ -114,6 +124,18 @@
boolean activityIn;
boolean activityOut;
String wifiSignalContentDescription;
+
+ @Override
+ public String toString() {
+ return new StringBuilder("CallbackInfo[")
+ .append("enabled=").append(enabled)
+ .append(",wifiSignalIconId=").append(wifiSignalIconId)
+ .append(",enabledDesc=").append(enabledDesc)
+ .append(",activityIn=").append(activityIn)
+ .append(",activityOut=").append(activityOut)
+ .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
+ .append(']').toString();
+ }
}
private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
@@ -121,6 +143,7 @@
public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
boolean activityIn, boolean activityOut,
String wifiSignalContentDescriptionId, String description) {
+ if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
final CallbackInfo info = new CallbackInfo();
info.enabled = enabled;
info.wifiSignalIconId = wifiSignalIconId;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
index dceb856..2edefe7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
@@ -32,6 +32,7 @@
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RelativeLayout;
@@ -39,7 +40,6 @@
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.qs.QSImageView;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -72,9 +72,7 @@
mContext = getContext();
mController = mHost.getZenModeController();
- final QSImageView close = (QSImageView) findViewById(android.R.id.button1);
- close.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_close));
- close.setEnabledVersion(true);
+ final ImageView close = (ImageView) findViewById(android.R.id.button1);
close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -239,9 +237,7 @@
title.setText(condition.summary);
title.setEnabled(enabled);
title.setAlpha(enabled ? 1 : .5f);
- final QSImageView button1 = (QSImageView) row.findViewById(android.R.id.button1);
- button1.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_minus));
- button1.setEnabledVersion(true);
+ final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -250,9 +246,7 @@
}
});
- final QSImageView button2 = (QSImageView) row.findViewById(android.R.id.button2);
- button2.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_plus));
- button2.setEnabledVersion(true);
+ final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
index 83918e8..bfa9c19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles;
import android.content.Context;
+import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -33,7 +34,6 @@
public ZenModeTile(Host host) {
super(host);
mController = host.getZenModeController();
- mController.addCallback(mCallback);
}
@Override
@@ -51,8 +51,12 @@
}
@Override
- public void dispose() {
- mController.removeCallback(mCallback);
+ public void setListening(boolean listening) {
+ if (listening) {
+ mController.addCallback(mCallback);
+ } else {
+ mController.removeCallback(mCallback);
+ }
}
@Override
@@ -69,14 +73,14 @@
final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
state.value = zen;
state.visible = true;
- state.iconId = R.drawable.stat_sys_zen_limited;
- state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_zen);
+ state.iconId = zen ? R.drawable.ic_qs_zen_on : R.drawable.ic_qs_zen_off;
state.label = mContext.getString(R.string.zen_mode_title);
}
private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
@Override
public void onZenChanged(boolean zen) {
+ if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
refreshState(zen);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index ae18aa8..00c43e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -27,7 +27,6 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -44,14 +43,12 @@
private static final boolean DEBUG = true;
// Which recents to use
- boolean mUseAlternateRecents;
+ boolean mUseAlternateRecents = true;
AlternateRecentsComponent mAlternateRecents;
boolean mBootCompleted = false;
@Override
public void start() {
- Configuration config = mContext.getResources().getConfiguration();
- mUseAlternateRecents = (config.smallestScreenWidthDp < 600);
if (mUseAlternateRecents) {
if (mAlternateRecents == null) {
mAlternateRecents = new AlternateRecentsComponent(mContext);
@@ -68,10 +65,30 @@
}
@Override
+ public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
+ if (mUseAlternateRecents) {
+ mAlternateRecents.onShowRecents(triggeredFromAltTab, statusBarView);
+ }
+ }
+
+ @Override
+ public void hideRecents() {
+ if (mUseAlternateRecents) {
+ mAlternateRecents.onHideRecents();
+ } else {
+ Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
+ intent.setPackage("com.android.systemui");
+ sendBroadcastSafely(intent);
+
+ RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
+ }
+ }
+
+ @Override
public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
if (mUseAlternateRecents) {
// Launch the alternate recents if required
- mAlternateRecents.onToggleRecents(display, layoutDirection, statusBarView);
+ mAlternateRecents.onToggleRecents(statusBarView);
return;
}
@@ -224,7 +241,7 @@
}
@Override
- public void preloadRecentTasksList() {
+ public void preloadRecents() {
if (mUseAlternateRecents) {
mAlternateRecents.onPreloadRecents();
} else {
@@ -238,7 +255,7 @@
}
@Override
- public void cancelPreloadingRecentTasksList() {
+ public void cancelPreloadingRecents() {
if (mUseAlternateRecents) {
mAlternateRecents.onCancelPreloadingRecents();
} else {
@@ -251,19 +268,6 @@
}
}
- @Override
- public void closeRecents() {
- if (mUseAlternateRecents) {
- mAlternateRecents.onCloseRecents();
- } else {
- Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
- intent.setPackage("com.android.systemui");
- sendBroadcastSafely(intent);
-
- RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
- }
- }
-
/**
* Send broadcast only if BOOT_COMPLETED
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 19a1b11..ec50bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -44,9 +44,9 @@
import android.view.WindowManager;
import com.android.systemui.R;
-import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
/** A proxy implementation for the recents component */
public class AlternateRecentsComponent {
@@ -72,7 +72,7 @@
// If we had the update the animation rects as a result of onServiceConnected, then
// we check for whether we need to toggle the recents here.
if (mToggleRecentsUponServiceBound) {
- startAlternateRecentsActivity();
+ startRecentsActivity();
mToggleRecentsUponServiceBound = false;
}
}
@@ -90,9 +90,9 @@
mServiceIsBound = true;
if (hasValidTaskRects()) {
- // Toggle recents if this new service connection was triggered by hitting recents
+ // Start recents if this new service connection was triggered by hitting recents
if (mToggleRecentsUponServiceBound) {
- startAlternateRecentsActivity();
+ startRecentsActivity();
mToggleRecentsUponServiceBound = false;
}
} else {
@@ -114,10 +114,12 @@
final public static int MSG_UPDATE_TASK_THUMBNAIL = 1;
final public static int MSG_PRELOAD_TASKS = 2;
final public static int MSG_CANCEL_PRELOAD_TASKS = 3;
- final public static int MSG_CLOSE_RECENTS = 4;
- final public static int MSG_TOGGLE_RECENTS = 5;
+ final public static int MSG_SHOW_RECENTS = 4;
+ final public static int MSG_HIDE_RECENTS = 5;
+ final public static int MSG_TOGGLE_RECENTS = 6;
final public static String EXTRA_ANIMATING_WITH_THUMBNAIL = "recents.animatingWithThumbnail";
+ final public static String EXTRA_FROM_ALT_TAB = "recents.triggeredFromAltTab";
final public static String KEY_CONFIGURATION_DATA = "recents.data.updateForConfiguration";
final public static String KEY_WINDOW_RECT = "recents.windowRect";
final public static String KEY_SYSTEM_INSETS = "recents.systemInsets";
@@ -142,7 +144,10 @@
boolean mToggleRecentsUponServiceBound;
RecentsServiceConnection mConnection = new RecentsServiceConnection();
+ // Variables to keep track of if we need to start recents after binding
View mStatusBarView;
+ boolean mTriggeredFromAltTab;
+
Rect mSingleCountFirstTaskRect = new Rect();
Rect mMultipleCountFirstTaskRect = new Rect();
long mLastToggleTime;
@@ -160,15 +165,11 @@
bindToRecentsService(false);
}
- /** Toggles the alternate recents activity */
- public void onToggleRecents(Display display, int layoutDirection, View statusBarView) {
- 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]",
- "serviceIsBound: " + mServiceIsBound);
+ /** Shows the recents */
+ public void onShowRecents(boolean triggeredFromAltTab, View statusBarView) {
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|showRecents]");
mStatusBarView = statusBarView;
+ mTriggeredFromAltTab = triggeredFromAltTab;
if (!mServiceIsBound) {
// Try to create a long-running connection to the recents service before toggling
// recents
@@ -177,7 +178,47 @@
}
try {
- startAlternateRecentsActivity();
+ startRecentsActivity();
+ } catch (ActivityNotFoundException e) {
+ Console.logRawError("Failed to launch RecentAppsIntent", e);
+ }
+ }
+
+ /** Hides the recents */
+ public void onHideRecents() {
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]");
+ if (mServiceIsBound) {
+ // Notify recents to close it
+ try {
+ Bundle data = new Bundle();
+ Message msg = Message.obtain(null, MSG_HIDE_RECENTS, 0, 0);
+ msg.setData(data);
+ mService.send(msg);
+ } catch (RemoteException re) {
+ re.printStackTrace();
+ }
+ }
+ }
+
+ /** Toggles the alternate recents activity */
+ public void onToggleRecents(View statusBarView) {
+ 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]",
+ "serviceIsBound: " + mServiceIsBound);
+ mStatusBarView = statusBarView;
+ mTriggeredFromAltTab = false;
+ if (!mServiceIsBound) {
+ // Try to create a long-running connection to the recents service before toggling
+ // recents
+ bindToRecentsService(true);
+ return;
+ }
+
+ try {
+ toggleRecentsActivity();
} catch (ActivityNotFoundException e) {
Console.logRawError("Failed to launch RecentAppsIntent", e);
}
@@ -191,21 +232,6 @@
// Do nothing
}
- public void onCloseRecents() {
- Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|closeRecents]");
- if (mServiceIsBound) {
- // Try and update the recents configuration
- try {
- Bundle data = new Bundle();
- Message msg = Message.obtain(null, MSG_CLOSE_RECENTS, 0, 0);
- msg.setData(data);
- mService.send(msg);
- } catch (RemoteException re) {
- re.printStackTrace();
- }
- }
- }
-
public void onConfigurationChanged(Configuration newConfig) {
updateAnimationRects();
}
@@ -355,8 +381,32 @@
taskRect.left, taskRect.top, null);
}
- /** Starts the recents activity */
- void startAlternateRecentsActivity() {
+ /** Returns whether the recents is currently running */
+ boolean isRecentsTopMost(AtomicBoolean isHomeTopMost) {
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
+ if (!tasks.isEmpty()) {
+ ActivityManager.RunningTaskInfo topTask = tasks.get(0);
+ ComponentName topActivity = topTask.topActivity;
+
+ // Check if the front most activity is recents
+ if (topActivity.getPackageName().equals(sRecentsPackage) &&
+ topActivity.getClassName().equals(sRecentsActivity)) {
+ if (isHomeTopMost != null) {
+ isHomeTopMost.set(false);
+ }
+ return true;
+ }
+
+ if (isHomeTopMost != null) {
+ isHomeTopMost.set(ssp.isInHomeStack(topTask.id));
+ }
+ }
+ return false;
+ }
+
+ /** Toggles the recents activity */
+ void toggleRecentsActivity() {
// If the user has toggled it too quickly, then just eat up the event here (it's better than
// showing a janky screenshot).
// NOTE: Ideally, the screenshot mechanism would take the window transform into account
@@ -366,43 +416,47 @@
// If Recents is the front most activity, then we should just communicate with it directly
// to launch the first task or dismiss itself
- SystemServicesProxy ssp = mSystemServicesProxy;
- List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
- boolean isTopTaskHome = false;
- if (!tasks.isEmpty()) {
- ActivityManager.RunningTaskInfo topTask = tasks.get(0);
- ComponentName topActivity = topTask.topActivity;
+ AtomicBoolean isTopTaskHome = new AtomicBoolean();
+ if (isRecentsTopMost(isTopTaskHome)) {
+ // Notify recents to close itself
+ try {
+ Bundle data = new Bundle();
+ Message msg = Message.obtain(null, MSG_TOGGLE_RECENTS, 0, 0);
+ msg.setData(data);
+ mService.send(msg);
- // Check if the front most activity is recents
- if (topActivity.getPackageName().equals(sRecentsPackage) &&
- topActivity.getClassName().equals(sRecentsActivity)) {
- // Notify Recents to toggle itself
- try {
- Bundle data = new Bundle();
- Message msg = Message.obtain(null, MSG_TOGGLE_RECENTS, 0, 0);
- msg.setData(data);
- mService.send(msg);
-
- // Time this path
- Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
- Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
- Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
- Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
- } catch (RemoteException re) {
- re.printStackTrace();
- }
- mLastToggleTime = System.currentTimeMillis();
- return;
+ // Time this path
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
+ } catch (RemoteException re) {
+ re.printStackTrace();
}
-
- // Determine whether the top task is currently home
- isTopTaskHome = ssp.isInHomeStack(topTask.id);
+ mLastToggleTime = System.currentTimeMillis();
+ return;
+ } else {
+ // Otherwise, start the recents activity
+ startRecentsActivity(isTopTaskHome.get());
}
+ }
- // Otherwise, Recents is not the front-most activity and we should animate into it. If
+ /** Starts the recents activity if it is not already running */
+ void startRecentsActivity() {
+ // Check if the top task is in the home stack, and start the recents activity
+ AtomicBoolean isTopTaskHome = new AtomicBoolean();
+ if (!isRecentsTopMost(isTopTaskHome)) {
+ startRecentsActivity(isTopTaskHome.get());
+ }
+ }
+
+ /** Starts the recents activity */
+ void startRecentsActivity(boolean isTopTaskHome) {
+ // If Recents is not the front-most activity and we should animate into it. If
// the activity at the root of the top task stack in the home stack, then we just do a
// simple transition. Otherwise, we animate to the rects defined by the Recents service,
// which can differ depending on the number of items in the list.
+ SystemServicesProxy ssp = mSystemServicesProxy;
List<ActivityManager.RecentTaskInfo> recentTasks =
ssp.getRecentTasks(2, UserHandle.CURRENT.getIdentifier());
Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
@@ -422,9 +476,6 @@
}
// If there is no thumbnail transition, then just use a generic transition
- // XXX: This should be different between home and from a recents-excluded app, perhaps the
- // recents-excluded app should still show up in recents, when the app is in the
- // foreground
if (!useThumbnailTransition) {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_launcher_enter,
@@ -444,6 +495,7 @@
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.putExtra(EXTRA_ANIMATING_WITH_THUMBNAIL, animatingWithThumbnail);
+ intent.putExtra(EXTRA_FROM_ALT_TAB, mTriggeredFromAltTab);
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
UserHandle.USER_CURRENT));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 90998da..9390b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -69,6 +69,7 @@
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 {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b74f6ac..325e4b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -28,6 +28,7 @@
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Pair;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
@@ -81,7 +82,10 @@
String action = intent.getAction();
Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
- if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
+ if (action.equals(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY)) {
+ // Dismiss recents, launching the focused task
+ dismissRecentsIfVisible();
+ } else if (action.equals(RecentsService.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
@@ -105,6 +109,8 @@
RecentsConfiguration config = RecentsConfiguration.getInstance();
config.launchedWithThumbnailAnimation = launchIntent.getBooleanExtra(
AlternateRecentsComponent.EXTRA_ANIMATING_WITH_THUMBNAIL, false);
+ config.launchedFromAltTab = launchIntent.getBooleanExtra(
+ AlternateRecentsComponent.EXTRA_FROM_ALT_TAB, false);
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount);
@@ -184,7 +190,7 @@
int appWidgetId = config.searchBarAppWidgetId;
if (appWidgetId >= 0) {
Console.log(Constants.Log.App.SystemUIHandshake,
- "[RecentsActivity|onCreate|addSearchAppWidgetView]",
+ "[RecentsActivity|onCreate|addSearchAppWidgetView]",
"Id: " + appWidgetId,
Console.AnsiBlue);
mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
@@ -205,8 +211,10 @@
/** Dismisses recents if we are already visible and the intent is to toggle the recents view */
boolean dismissRecentsIfVisible() {
if (mVisible) {
- if (!mRecentsView.launchFirstTask()) {
- finish();
+ if (!mRecentsView.launchFocusedTask()) {
+ if (!mRecentsView.launchFirstTask()) {
+ finish();
+ }
}
return true;
}
@@ -303,6 +311,7 @@
// Register the broadcast receiver to handle messages from our service
IntentFilter filter = new IntentFilter();
+ filter.addAction(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY);
filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
registerReceiver(mServiceBroadcastReceiver, filter);
@@ -362,6 +371,18 @@
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_TAB) {
+ // Focus the next task in the stack
+ final boolean backward = event.isShiftPressed();
+ mRecentsView.focusNextTask(!backward);
+ return true;
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
public void onBackPressed() {
boolean interceptedByInfoPanelClose = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 9afc1cb..8399551 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -65,6 +65,7 @@
public int taskBarViewLightTextColor;
public int taskBarViewDarkTextColor;
+ public boolean launchedFromAltTab;
public boolean launchedWithThumbnailAnimation;
/** Private constructor */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 837cb34..601b382 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -106,8 +106,11 @@
} catch (RemoteException re) {
re.printStackTrace();
}
- } else if (msg.what == AlternateRecentsComponent.MSG_CLOSE_RECENTS) {
- // Do nothing
+ } else if (msg.what == AlternateRecentsComponent.MSG_HIDE_RECENTS) {
+ // Send a broadcast to hide recents
+ Intent intent = new Intent(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY);
+ intent.setPackage(context.getPackageName());
+ context.sendBroadcast(intent);
} else if (msg.what == AlternateRecentsComponent.MSG_TOGGLE_RECENTS) {
// Send a broadcast to toggle recents
Intent intent = new Intent(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
@@ -125,6 +128,7 @@
/* Service */
public class RecentsService extends Service {
+ final static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
final static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
Messenger mSystemUIMessenger = new Messenger(new SystemUIMessageHandler(this));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 1ca0476..1c12ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -400,15 +400,14 @@
ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
if (info == null) continue;
- ActivityManager.RecentsActivityValues av = t.activityValues;
+ ActivityManager.TaskDescription av = t.taskDescription;
String activityLabel = null;
BitmapDrawable activityIcon = null;
int activityColor = 0;
if (av != null) {
- activityLabel = (av.label != null ? av.label.toString() :
- ssp.getActivityLabel(info));
- activityIcon = (av.icon != null) ? new BitmapDrawable(res, av.icon) : null;
- activityColor = av.colorPrimary;
+ activityLabel = (av.getLabel() != null ? av.getLabel() : ssp.getActivityLabel(info));
+ activityIcon = (av.getIcon() != null) ? new BitmapDrawable(res, av.getIcon()) : null;
+ activityColor = av.getPrimaryColor();
} else {
activityLabel = ssp.getActivityLabel(info);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 8d82883..59d0ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -96,18 +96,19 @@
int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
ComponentName cn = new ComponentName("com.android.test" + packageIndex,
"com.android.test" + i + ".Activity");
+ String description = "" + i + " - " +
+ Long.toString(Math.abs(new Random().nextLong()), 36);
// Create the recent task info
ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
rti.id = rti.persistentId = i;
rti.baseIntent = new Intent();
rti.baseIntent.setComponent(cn);
- rti.activityValues = new ActivityManager.RecentsActivityValues();
- rti.description = "" + i + " - " +
- Long.toString(Math.abs(new Random().nextLong()), 36);
+ rti.description = description;
if (i % 2 == 0) {
- rti.activityValues.label = rti.description;
- rti.activityValues.icon = Bitmap.createBitmap(mDummyIcon);
- rti.activityValues.colorPrimary = new Random().nextInt();
+ rti.taskDescription = new ActivityManager.TaskDescription(description,
+ Bitmap.createBitmap(mDummyIcon), new Random().nextInt());
+ } else {
+ rti.taskDescription = new ActivityManager.TaskDescription();
}
tasks.add(rti);
}
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 a6d7e67..2821052 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -94,6 +94,34 @@
}
}
+ /** Launches the focused task from the first stack if possible */
+ public boolean launchFocusedTask() {
+ // Get the first stack view
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView) {
+ TaskStackView stackView = (TaskStackView) child;
+ TaskStack stack = stackView.mStack;
+ // Iterate the stack views and try and find the focused task
+ int taskCount = stackView.getChildCount();
+ for (int j = 0; j < taskCount; j++) {
+ TaskView tv = (TaskView) stackView.getChildAt(j);
+ Task task = tv.getTask();
+ if (tv.isFocusedTask()) {
+ Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
+ "Found focused Task");
+ onTaskLaunched(stackView, tv, stack, task);
+ return true;
+ }
+ }
+ }
+ }
+ Console.log(Constants.Log.UI.Focus, "[RecentsView|launchFocusedTask]",
+ "No Tasks focused");
+ return false;
+ }
+
/** Launches the first task from the first stack if possible */
public boolean launchFirstTask() {
// Get the first stack view
@@ -234,6 +262,24 @@
}
}
+ /** Focuses the next task in the first stack view */
+ public void focusNextTask(boolean forward) {
+ // Get the first stack view
+ TaskStackView stackView = null;
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView) {
+ stackView = (TaskStackView) child;
+ break;
+ }
+ }
+
+ if (stackView != null) {
+ stackView.focusNextTask(forward);
+ }
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
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 b64225e..37c3c35 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -80,6 +80,7 @@
int mMaxScroll;
int mStashedScroll;
int mLastInfoPaneStackScroll;
+ int mFocusedTaskIndex = -1;
OverScroller mScroller;
ObjectAnimator mScrollAnimator;
@@ -306,6 +307,15 @@
mStackScroll = value;
}
+ /**
+ * Returns the scroll to such that the task transform at that index will have t=0. (If the scroll
+ * is not bounded)
+ */
+ int getStackScrollForTaskIndex(int i) {
+ int taskHeight = mTaskRect.height();
+ return (int) (i * Constants.Values.TaskStackView.StackOverlapPct * taskHeight);
+ }
+
/** Gets the current stack scroll */
public int getStackScroll() {
return mStackScroll;
@@ -460,6 +470,64 @@
return false;
}
+ /** Focuses the task at the specified index in the stack */
+ void focusTask(int taskIndex, boolean scrollToNewPosition) {
+ Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "" + taskIndex);
+ if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
+ mFocusedTaskIndex = taskIndex;
+
+ // Focus the view if possible, otherwise, focus the view after we scroll into position
+ Task t = mStack.getTasks().get(taskIndex);
+ TaskView tv = getChildViewForTask(t);
+ Runnable postScrollRunnable = null;
+ if (tv != null) {
+ tv.setFocusedTask();
+ Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]", "Requesting focus");
+ } else {
+ postScrollRunnable = new Runnable() {
+ @Override
+ public void run() {
+ Task t = mStack.getTasks().get(mFocusedTaskIndex);
+ TaskView tv = getChildViewForTask(t);
+ if (tv != null) {
+ tv.setFocusedTask();
+ Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusTask]",
+ "Requesting focus after scroll animation");
+ }
+ }
+ };
+ }
+
+ if (scrollToNewPosition) {
+ // Scroll the view into position
+ int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll,
+ getStackScrollForTaskIndex(taskIndex)));
+
+ animateScroll(getStackScroll(), newScroll, postScrollRunnable);
+ } else {
+ if (postScrollRunnable != null) {
+ postScrollRunnable.run();
+ }
+ }
+ }
+ }
+
+ /** Focuses the next task in the stack */
+ void focusNextTask(boolean forward) {
+ Console.log(Constants.Log.UI.Focus, "[TaskStackView|focusNextTask]", "" + mFocusedTaskIndex);
+
+ // Find the next index to focus
+ int numTasks = mStack.getTaskCount();
+ if (mFocusedTaskIndex < 0) {
+ mFocusedTaskIndex = numTasks - 1;
+ }
+ if (0 <= mFocusedTaskIndex && mFocusedTaskIndex < numTasks) {
+ mFocusedTaskIndex = Math.max(0, Math.min(numTasks - 1,
+ mFocusedTaskIndex + (forward ? -1 : 1)));
+ }
+ focusTask(mFocusedTaskIndex, true);
+ }
+
/** Enables the hw layers and increments the hw layer requirement ref count */
void addHwLayersRefCount(String reason) {
Console.log(Constants.Log.UI.HwLayers,
@@ -631,6 +699,11 @@
requestSynchronizeStackViewsWithModel();
synchronizeStackViewsWithModel();
+ // Update the focused task index to be the next item to the top task
+ if (config.launchedFromAltTab) {
+ focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
+ }
+
// Animate the task bar of the first task view
if (config.launchedWithThumbnailAnimation) {
TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
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 5fad629..ffcb82b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -18,6 +18,7 @@
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Outline;
@@ -57,6 +58,7 @@
Task mTask;
boolean mTaskDataLoaded;
boolean mTaskInfoPaneVisible;
+ boolean mIsFocused;
Point mLastTouchDown = new Point();
Path mRoundedRectClipPath = new Path();
@@ -367,6 +369,34 @@
}
}
+ /**
+ * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
+ * if the view is not currently visible, or we are in touch state (where we still want to keep
+ * track of focus).
+ */
+ public void setFocusedTask() {
+ mIsFocused = true;
+ requestFocus();
+ }
+
+ /**
+ * Updates the explicitly focused state when the view focus changes.
+ */
+ @Override
+ protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ if (!gainFocus) {
+ mIsFocused = false;
+ }
+ }
+
+ /**
+ * Returns whether we have explicitly been focused.
+ */
+ public boolean isFocusedTask() {
+ return mIsFocused || isFocused();
+ }
+
/**** TaskCallbacks Implementation ****/
/** Binds this task view to the task */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 91df9ef..5e8c769 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -21,6 +21,7 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -45,6 +46,9 @@
private int mBgResId = R.drawable.notification_quantum_bg;
private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
+ private int mBgTint = 0;
+ private int mDimmedBgTint = 0;
+
/**
* Flag to indicate that the notification has been touched once and the second touch will
* click it.
@@ -209,17 +213,23 @@
* @param bgResId The background resource to use in normal state.
* @param dimmedBgResId The background resource to use in dimmed state.
*/
- public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
+ public void setBackgroundResourceIds(int bgResId, int bgTint, int dimmedBgResId, int dimmedTint) {
mBgResId = bgResId;
+ mBgTint = bgTint;
mDimmedBgResId = dimmedBgResId;
+ mDimmedBgTint = dimmedTint;
updateBackgroundResource();
}
+ public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
+ setBackgroundResourceIds(bgResId, 0, dimmedBgResId, 0);
+ }
+
private void fadeBackgroundResource() {
if (mDimmed) {
- setBackgroundDimmed(mDimmedBgResId);
+ setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
} else {
- setBackgroundNormal(mBgResId);
+ setBackgroundNormal(mBgResId, mBgTint);
}
int startAlpha = mDimmed ? 255 : 0;
int endAlpha = mDimmed ? 0 : 255;
@@ -256,12 +266,12 @@
private void updateBackgroundResource() {
if (mDimmed) {
- setBackgroundDimmed(mDimmedBgResId);
+ setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
mBackgroundDimmed.setAlpha(255);
setBackgroundNormal(null);
} else {
setBackgroundDimmed(null);
- setBackgroundNormal(mBgResId);
+ setBackgroundNormal(mBgResId, mBgTint);
mBackgroundNormal.setAlpha(255);
}
}
@@ -295,12 +305,20 @@
invalidate();
}
- private void setBackgroundNormal(int drawableResId) {
- setBackgroundNormal(getResources().getDrawable(drawableResId));
+ private void setBackgroundNormal(int drawableResId, int tintColor) {
+ final Drawable d = getResources().getDrawable(drawableResId);
+ if (tintColor != 0) {
+ d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
+ }
+ setBackgroundNormal(d);
}
- private void setBackgroundDimmed(int drawableResId) {
- setBackgroundDimmed(getResources().getDrawable(drawableResId));
+ private void setBackgroundDimmed(int drawableResId, int tintColor) {
+ final Drawable d = getResources().getDrawable(drawableResId);
+ if (tintColor != 0) {
+ d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
+ }
+ setBackgroundDimmed(d);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 898f06e..7918dec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -87,8 +87,9 @@
public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
- protected static final int MSG_TOGGLE_RECENTS_PANEL = 1020;
- protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
+ protected static final int MSG_SHOW_RECENT_APPS = 1019;
+ protected static final int MSG_HIDE_RECENT_APPS = 1020;
+ protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
@@ -428,14 +429,16 @@
protected void applyLegacyRowBackground(StatusBarNotification sbn,
NotificationData.Entry entry) {
+ int version = 0;
+ try {
+ ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
+ version = info.targetSdkVersion;
+ } catch (NameNotFoundException ex) {
+ Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
+ }
+
if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
- int version = 0;
- try {
- ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
- version = info.targetSdkVersion;
- } catch (NameNotFoundException ex) {
- Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
- }
+ // Using custom RemoteViews
if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
entry.row.setBackgroundResource(R.drawable.notification_row_legacy_bg);
} else if (version < Build.VERSION_CODES.L) {
@@ -494,8 +497,22 @@
}
@Override
+ public void showRecentApps(boolean triggeredFromAltTab) {
+ int msg = MSG_SHOW_RECENT_APPS;
+ mHandler.removeMessages(msg);
+ mHandler.obtainMessage(msg, triggeredFromAltTab ? 1 : 0, 0).sendToTarget();
+ }
+
+ @Override
+ public void hideRecentApps() {
+ int msg = MSG_HIDE_RECENT_APPS;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ @Override
public void toggleRecentApps() {
- int msg = MSG_TOGGLE_RECENTS_PANEL;
+ int msg = MSG_TOGGLE_RECENTS_APPS;
mHandler.removeMessages(msg);
mHandler.sendEmptyMessage(msg);
}
@@ -578,12 +595,12 @@
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN) {
- preloadRecentTasksList();
+ preloadRecents();
} else if (action == MotionEvent.ACTION_CANCEL) {
- cancelPreloadingRecentTasksList();
+ cancelPreloadingRecents();
} else if (action == MotionEvent.ACTION_UP) {
if (!v.isPressed()) {
- cancelPreloadingRecentTasksList();
+ cancelPreloadingRecents();
}
}
@@ -591,28 +608,38 @@
}
};
- protected void toggleRecentsActivity() {
+ /** Proxy for RecentsComponent */
+
+ protected void showRecents(boolean triggeredFromAltTab) {
+ if (mRecents != null) {
+ sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
+ mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
+ }
+ }
+
+ protected void hideRecents() {
+ if (mRecents != null) {
+ sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
+ mRecents.hideRecents();
+ }
+ }
+
+ protected void toggleRecents() {
if (mRecents != null) {
sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
}
}
- protected void preloadRecentTasksList() {
+ protected void preloadRecents() {
if (mRecents != null) {
- mRecents.preloadRecentTasksList();
+ mRecents.preloadRecents();
}
}
- protected void cancelPreloadingRecentTasksList() {
+ protected void cancelPreloadingRecents() {
if (mRecents != null) {
- mRecents.cancelPreloadingRecentTasksList();
- }
- }
-
- protected void closeRecents() {
- if (mRecents != null) {
- mRecents.closeRecents();
+ mRecents.cancelPreloadingRecents();
}
}
@@ -653,17 +680,20 @@
public void handleMessage(Message m) {
Intent intent;
switch (m.what) {
- case MSG_TOGGLE_RECENTS_PANEL:
- toggleRecentsActivity();
+ case MSG_SHOW_RECENT_APPS:
+ showRecents(m.arg1 > 0);
break;
- case MSG_CLOSE_RECENTS_PANEL:
- closeRecents();
+ case MSG_HIDE_RECENT_APPS:
+ hideRecents();
+ break;
+ case MSG_TOGGLE_RECENTS_APPS:
+ toggleRecents();
break;
case MSG_PRELOAD_RECENT_APPS:
- preloadRecentTasksList();
+ preloadRecents();
break;
case MSG_CANCEL_PRELOAD_RECENT_APPS:
- cancelPreloadingRecentTasksList();
+ cancelPreloadingRecents();
break;
case MSG_OPEN_SEARCH_PANEL:
if (DEBUG) Log.d(TAG, "opening search panel");
@@ -875,6 +905,7 @@
entry.row = row;
entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
entry.row.setOnActivatedListener(this);
+ entry.row.setIsBelowSpeedBump(isBelowSpeedBump(entry.notification));
entry.expanded = contentViewLocal;
entry.expandedPublic = publicViewLocal;
entry.setBigContentView(bigContentViewLocal);
@@ -1037,8 +1068,8 @@
if (DEBUG) {
Log.d(TAG, "addNotificationViews: added at " + pos);
}
- updateRowStates();
updateNotificationIcons();
+ updateRowStates();
}
private void addNotificationViews(IBinder key, StatusBarNotification notification) {
@@ -1058,6 +1089,7 @@
mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
int n = mNotificationData.size();
int visibleNotifications = 0;
+ int speedBumpIndex = -1;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
for (int i = n-1; i >= 0; i--) {
NotificationData.Entry entry = mNotificationData.get(i);
@@ -1085,6 +1117,10 @@
entry.row.setVisibility(View.VISIBLE);
visibleNotifications++;
}
+ if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1
+ && entry.row.isBelowSpeedBump() ) {
+ speedBumpIndex = n - 1 - i;
+ }
}
if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
@@ -1092,6 +1128,8 @@
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
}
+
+ mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
}
private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1307,9 +1345,19 @@
} else {
entry.row.setOnClickListener(null);
}
+ boolean wasBelow = entry.row.isBelowSpeedBump();
+ boolean nowBelow = isBelowSpeedBump(notification);
+ if (wasBelow != nowBelow) {
+ entry.row.setIsBelowSpeedBump(nowBelow);
+ }
entry.row.notifyContentUpdated();
}
+ private boolean isBelowSpeedBump(StatusBarNotification notification) {
+ return notification.getNotification().priority ==
+ Notification.PRIORITY_MIN;
+ }
+
protected void notifyHeadsUpScreenOn(boolean screenOn) {
if (!screenOn && mInterruptingNotificationEntry != null) {
mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 5362af5..ebab7fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -57,6 +57,8 @@
private static final int MSG_PRELOAD_RECENT_APPS = 14 << MSG_SHIFT;
private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 15 << MSG_SHIFT;
private static final int MSG_SET_WINDOW_STATE = 16 << MSG_SHIFT;
+ private static final int MSG_SHOW_RECENT_APPS = 17 << MSG_SHIFT;
+ private static final int MSG_HIDE_RECENT_APPS = 18 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -96,11 +98,13 @@
public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
public void setHardKeyboardStatus(boolean available, boolean enabled);
+ public void showRecentApps(boolean triggeredFromAltTab);
+ public void hideRecentApps();
public void toggleRecentApps();
public void preloadRecentApps();
+ public void cancelPreloadRecentApps();
public void showSearchPanel();
public void hideSearchPanel();
- public void cancelPreloadRecentApps();
public void setWindowState(int window, int state);
}
@@ -211,6 +215,21 @@
}
}
+ public void showRecentApps(boolean triggeredFromAltTab) {
+ synchronized (mList) {
+ mHandler.removeMessages(MSG_SHOW_RECENT_APPS);
+ mHandler.obtainMessage(MSG_SHOW_RECENT_APPS,
+ triggeredFromAltTab ? 1 : 0, 0, null).sendToTarget();
+ }
+ }
+
+ public void hideRecentApps() {
+ synchronized (mList) {
+ mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
+ mHandler.obtainMessage(MSG_HIDE_RECENT_APPS, 0, 0, null).sendToTarget();
+ }
+ }
+
public void toggleRecentApps() {
synchronized (mList) {
mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
@@ -309,6 +328,12 @@
case MSG_SET_HARD_KEYBOARD_STATUS:
mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
break;
+ case MSG_SHOW_RECENT_APPS:
+ mCallbacks.showRecentApps(msg.arg1 != 0);
+ break;
+ case MSG_HIDE_RECENT_APPS:
+ mCallbacks.hideRecentApps();
+ break;
case MSG_TOGGLE_RECENT_APPS:
mCallbacks.toggleRecentApps();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 39f2bb9..f6c80fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,6 +52,7 @@
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
private int mMaxExpandHeight;
+ private boolean mIsBelowSpeedBump;
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -244,6 +245,14 @@
mPrivateLayout.setClipTopAmount(clipTopAmount);
}
+ public boolean isBelowSpeedBump() {
+ return mIsBelowSpeedBump;
+ }
+
+ public void setIsBelowSpeedBump(boolean isBelow) {
+ this.mIsBelowSpeedBump = isBelow;
+ }
+
public void notifyContentUpdated() {
mPrivateLayout.notifyContentUpdated();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 4bd0e1c..061396d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -40,11 +40,15 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!mActualHeightInitialized && mActualHeight == 0) {
- mActualHeight = getHeight();
+ mActualHeight = getInitialHeight();
}
mActualHeightInitialized = true;
}
+ protected int getInitialHeight() {
+ return getHeight();
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (filterMotionEvent(ev)) {
@@ -146,6 +150,10 @@
}
}
+ public boolean isTransparent() {
+ return false;
+ }
+
/**
* A listener notifying when {@link #getActualHeight} changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 6401695..9c39002 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -89,7 +89,7 @@
return;
}
final Notification n = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.stat_sys_zen_limited)
+ .setSmallIcon(R.drawable.ic_qs_zen_on)
.setContentTitle(mContext.getResources().getQuantityString(
R.plurals.zen_mode_notification_title,
mIntercepted.size(), mIntercepted.size()))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
new file mode 100644
index 0000000..3ca021a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
@@ -0,0 +1,47 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * An single dot of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
+ */
+public class SpeedBumpDotView extends View {
+
+ private final Paint mPaint = new Paint();
+
+ public SpeedBumpDotView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mPaint.setAntiAlias(true);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ float radius = getWidth() / 2.0f;
+ canvas.drawCircle(radius, radius, radius, mPaint);
+ }
+
+ public void setColor(int color) {
+ mPaint.setColor(color);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
new file mode 100644
index 0000000..cac6327
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
@@ -0,0 +1,80 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.R;
+
+/**
+ * The Algorithm of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout} which can be
+ * queried for {@link * com.android.systemui.statusbar.SpeedBumpDotsState}
+ */
+public class SpeedBumpDotsAlgorithm {
+
+ private final float mDotRadius;
+
+ public SpeedBumpDotsAlgorithm(Context context) {
+ mDotRadius = context.getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height)
+ / 2.0f;
+ }
+
+ public void getState(SpeedBumpDotsState resultState) {
+
+ // First reset the current state and ensure that every View has a ViewState
+ resultState.resetViewStates();
+
+ SpeedBumpDotsLayout hostView = resultState.getHostView();
+ boolean currentlyVisible = hostView.isCurrentlyVisible();
+ resultState.setActiveState(currentlyVisible
+ ? SpeedBumpDotsState.SHOWN
+ : SpeedBumpDotsState.HIDDEN);
+ int hostWidth = hostView.getWidth();
+ float layoutWidth = hostWidth - 2 * mDotRadius;
+ int childCount = hostView.getChildCount();
+ float paddingBetween = layoutWidth / (childCount - 1);
+ float centerY = hostView.getHeight() / 2.0f;
+ for (int i = 0; i < childCount; i++) {
+ View child = hostView.getChildAt(i);
+ SpeedBumpDotsState.ViewState viewState = resultState.getViewStateForView(child);
+ if (currentlyVisible) {
+ float xTranslation = i * paddingBetween;
+ viewState.xTranslation = xTranslation;
+ viewState.yTranslation = calculateYTranslation(hostView, centerY, xTranslation,
+ layoutWidth);
+ } else {
+ viewState.xTranslation = layoutWidth / 2;
+ viewState.yTranslation = centerY - mDotRadius;
+ }
+ viewState.alpha = currentlyVisible ? 1.0f : 0.0f;
+ viewState.scale = currentlyVisible ? 1.0f : 0.5f;
+ }
+ }
+
+ private float calculateYTranslation(SpeedBumpDotsLayout hostView, float centerY,
+ float xTranslation, float layoutWidth) {
+ float t = hostView.getAnimationProgress();
+ if (t == 0.0f || t == 1.0f) {
+ return centerY - mDotRadius;
+ }
+ float damping = (0.5f -Math.abs(0.5f - t)) * 1.3f;
+ float partialOffset = xTranslation / layoutWidth;
+ float indentFactor = (float) (Math.sin((t + partialOffset * 1.5f) * - Math.PI) * damping);
+ return (1.0f - indentFactor) * centerY - mDotRadius;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
new file mode 100644
index 0000000..ddf5215
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
@@ -0,0 +1,136 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import com.android.systemui.R;
+
+/**
+ * A layout with a certain number of dots which are integrated in the
+ * {@link com.android.systemui.statusbar.SpeedBumpView}
+ */
+public class SpeedBumpDotsLayout extends ViewGroup {
+
+ private static final float DOT_CLICK_ANIMATION_LENGTH = 300;
+ private final int mDotSize;
+ private final SpeedBumpDotsAlgorithm mAlgorithm = new SpeedBumpDotsAlgorithm(getContext());
+ private final SpeedBumpDotsState mCurrentState = new SpeedBumpDotsState(this);
+ private boolean mIsCurrentlyVisible = true;
+ private final ValueAnimator mClickAnimator;
+ private float mAnimationProgress;
+ private ValueAnimator.AnimatorUpdateListener mClickUpdateListener
+ = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mAnimationProgress = animation.getAnimatedFraction();
+ updateChildren();
+ }
+ };
+
+ public SpeedBumpDotsLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mDotSize = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
+ createDots(context, attrs);
+ mClickAnimator = TimeAnimator.ofFloat(0, DOT_CLICK_ANIMATION_LENGTH);
+ mClickAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
+ mClickAnimator.addUpdateListener(mClickUpdateListener);
+ }
+
+ private void createDots(Context context, AttributeSet attrs) {
+ SpeedBumpDotView blueDot = new SpeedBumpDotView(context, attrs);
+ blueDot.setColor(getResources().getColor(R.color.speed_bump_dot_blue));
+ addView(blueDot);
+
+ SpeedBumpDotView redDot = new SpeedBumpDotView(context, attrs);
+ redDot.setColor(getResources().getColor(R.color.speed_bump_dot_red));
+ addView(redDot);
+
+ SpeedBumpDotView yellowDot = new SpeedBumpDotView(context, attrs);
+ yellowDot.setColor(getResources().getColor(R.color.speed_bump_dot_yellow));
+ addView(yellowDot);
+
+ SpeedBumpDotView greenDot = new SpeedBumpDotView(context, attrs);
+ greenDot.setColor(getResources().getColor(R.color.speed_bump_dot_green));
+ addView(greenDot);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int childWidthSpec = MeasureSpec.makeMeasureSpec(mDotSize,
+ MeasureSpec.getMode(widthMeasureSpec));
+ int childHeightSpec = MeasureSpec.makeMeasureSpec(mDotSize,
+ MeasureSpec.getMode(heightMeasureSpec));
+ measureChildren(childWidthSpec, childHeightSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ child.layout(0, 0, mDotSize, mDotSize);
+ }
+ if (changed) {
+ updateChildren();
+ }
+ }
+
+ private void updateChildren() {
+ mAlgorithm.getState(mCurrentState);
+ mCurrentState.apply();
+ }
+
+ public void performVisibilityAnimation(boolean visible) {
+ if (mClickAnimator.isRunning()) {
+ mClickAnimator.cancel();
+ }
+ mIsCurrentlyVisible = visible;
+ mAlgorithm.getState(mCurrentState);
+ mCurrentState.animateToState();
+ }
+
+ public void setInvisible() {
+ mIsCurrentlyVisible = false;
+ mAlgorithm.getState(mCurrentState);
+ mCurrentState.apply();
+ }
+
+ public boolean isCurrentlyVisible() {
+ return mIsCurrentlyVisible;
+ }
+
+ public void performDotClickAnimation() {
+ if (mClickAnimator.isRunning()) {
+ // don't perform an animation if it's running already
+ return;
+ }
+ mClickAnimator.start();
+ }
+
+
+ public float getAnimationProgress() {
+ return mAnimationProgress;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
new file mode 100644
index 0000000..06a7f95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
@@ -0,0 +1,139 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A state of a {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
+ */
+public class SpeedBumpDotsState {
+
+ public static final int HIDDEN = 1;
+ public static final int SHOWN = 2;
+ private static final int VISIBILITY_ANIMATION_DELAY_PER_ELEMENT = 80;
+
+ private final SpeedBumpDotsLayout mHostView;
+ private final HashMap<View, ViewState> mStateMap = new HashMap<View, ViewState>();
+ private final Interpolator mFastOutSlowInInterpolator;
+ private int mActiveState = 0;
+
+ public SpeedBumpDotsState(SpeedBumpDotsLayout hostLayout) {
+ mHostView = hostLayout;
+ mFastOutSlowInInterpolator = AnimationUtils
+ .loadInterpolator(hostLayout.getContext(),
+ android.R.interpolator.fast_out_slow_in);
+ }
+
+ public SpeedBumpDotsLayout getHostView() {
+ return mHostView;
+ }
+
+ public void resetViewStates() {
+ int numChildren = mHostView.getChildCount();
+ for (int i = 0; i < numChildren; i++) {
+ View child = mHostView.getChildAt(i);
+ ViewState viewState = mStateMap.get(child);
+ if (viewState == null) {
+ viewState = new ViewState();
+ mStateMap.put(child, viewState);
+ }
+ }
+ }
+
+ public ViewState getViewStateForView(View requestedView) {
+ return mStateMap.get(requestedView);
+ }
+
+ public void apply() {
+ int childCount = mHostView.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = mHostView.getChildAt(i);
+ ViewState viewState = mStateMap.get(child);
+ float translationX = child.getTranslationX();
+ float translationY = child.getTranslationY();
+ float scale = child.getScaleX();
+ float alpha = child.getAlpha();
+ if (translationX != viewState.xTranslation) {
+ child.setTranslationX(viewState.xTranslation);
+ }
+ if (translationY != viewState.yTranslation) {
+ child.setTranslationY(viewState.yTranslation);
+ }
+ if (scale != viewState.scale) {
+ child.setScaleX(viewState.scale);
+ child.setScaleY(viewState.scale);
+ }
+ if (alpha != viewState.alpha) {
+ child.setAlpha(viewState.alpha);
+ }
+ }
+ }
+
+ public void animateToState() {
+ int childCount = mHostView.getChildCount();
+ int middleIndex = (childCount - 1) / 2;
+ long delayPerElement = VISIBILITY_ANIMATION_DELAY_PER_ELEMENT;
+ boolean isAppearing = getActiveState() == SHOWN;
+ boolean isDisappearing = getActiveState() == HIDDEN;
+ for (int i = 0; i < childCount; i++) {
+ int delayIndex;
+ if (i <= middleIndex) {
+ delayIndex = i * 2;
+ } else {
+ int distToMiddle = i - middleIndex;
+ delayIndex = (childCount - 1) - (distToMiddle - 1) * 2;
+ }
+ long startDelay = 0;
+ if (isAppearing || isDisappearing) {
+ if (isDisappearing) {
+ delayIndex = childCount - 1 - delayIndex;
+ }
+ startDelay = delayIndex * delayPerElement;
+ }
+ View child = mHostView.getChildAt(i);
+ ViewState viewState = mStateMap.get(child);
+ child.animate().setInterpolator(mFastOutSlowInInterpolator)
+ .setStartDelay(startDelay)
+ .alpha(viewState.alpha).withLayer()
+ .translationX(viewState.xTranslation)
+ .translationY(viewState.yTranslation)
+ .scaleX(viewState.scale).scaleY(viewState.scale);
+ }
+ }
+
+ public int getActiveState() {
+ return mActiveState;
+ }
+
+ public void setActiveState(int mActiveState) {
+ this.mActiveState = mActiveState;
+ }
+
+ public static class ViewState {
+ float xTranslation;
+ float yTranslation;
+ float alpha;
+ float scale;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
new file mode 100644
index 0000000..8ae503a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -0,0 +1,265 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Outline;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.TextView;
+import com.android.systemui.R;
+
+/**
+ * The view representing the separation between important and less important notifications
+ */
+public class SpeedBumpView extends ExpandableView implements View.OnClickListener {
+
+ private final int mCollapsedHeight;
+ private final int mDotsHeight;
+ private final int mTextPaddingInset;
+ private SpeedBumpDotsLayout mDots;
+ private View mLineLeft;
+ private View mLineRight;
+ private boolean mIsExpanded;
+ private boolean mDividerVisible = true;
+ private ValueAnimator mCurrentAnimator;
+ private final Interpolator mFastOutSlowInInterpolator;
+ private float mCenterX;
+ private TextView mExplanationText;
+ private boolean mExplanationTextVisible = false;
+ private AnimatorListenerAdapter mHideExplanationListener = new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCancelled) {
+ mExplanationText.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mCancelled = false;
+ }
+ };
+ private Animator.AnimatorListener mAnimationFinishedListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentAnimator = null;
+ }
+ };
+
+ public SpeedBumpView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mCollapsedHeight = getResources()
+ .getDimensionPixelSize(R.dimen.speed_bump_height_collapsed);
+ mTextPaddingInset = getResources().getDimensionPixelSize(
+ R.dimen.speed_bump_text_padding_inset);
+ mDotsHeight = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
+ setOnClickListener(this);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+ android.R.interpolator.fast_out_slow_in);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDots = (SpeedBumpDotsLayout) findViewById(R.id.speed_bump_dots_layout);
+ mLineLeft = findViewById(R.id.speedbump_line_left);
+ mLineRight = findViewById(R.id.speedbump_line_right);
+ mExplanationText = (TextView) findViewById(R.id.speed_bump_text);
+ resetExplanationText();
+
+ }
+
+ @Override
+ protected int getInitialHeight() {
+ return mCollapsedHeight;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return getActualHeight();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ Outline outline = new Outline();
+ mCenterX = getWidth() / 2;
+ float centerY = getHeight() / 2;
+ // TODO: hide outline better
+ // Temporary workaround to hide outline on a transparent view
+ int outlineLeft = (int) (mCenterX - getResources().getDisplayMetrics().densityDpi * 8);
+ int outlineTop = (int) (centerY - mDotsHeight / 2);
+ outline.setOval(outlineLeft, outlineTop, outlineLeft + mDotsHeight,
+ outlineTop + mDotsHeight);
+ setOutline(outline);
+ mLineLeft.setPivotX(mLineLeft.getWidth());
+ mLineLeft.setPivotY(mLineLeft.getHeight() / 2);
+ mLineRight.setPivotX(0);
+ mLineRight.setPivotY(mLineRight.getHeight() / 2);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ measureChildren(widthMeasureSpec, heightMeasureSpec);
+ int height = mCollapsedHeight + mExplanationText.getMeasuredHeight() - mTextPaddingInset;
+ setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (mCurrentAnimator != null) {
+ return;
+ }
+ int startValue = mIsExpanded ? getMaxHeight() : mCollapsedHeight;
+ int endValue = mIsExpanded ? mCollapsedHeight : getMaxHeight();
+ mCurrentAnimator = ValueAnimator.ofInt(startValue, endValue);
+ mCurrentAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setActualHeight((int) animation.getAnimatedValue());
+ }
+ });
+ mCurrentAnimator.addListener(mAnimationFinishedListener);
+ mCurrentAnimator.start();
+ mIsExpanded = !mIsExpanded;
+ mDots.performDotClickAnimation();
+ animateExplanationTextInternal(mIsExpanded);
+ }
+
+ private void animateExplanationTextInternal(boolean visible) {
+ if (mExplanationTextVisible != visible) {
+ float translationY = 0.0f;
+ float scale = 0.5f;
+ float alpha = 0.0f;
+ boolean needsHideListener = true;
+ if (visible) {
+ mExplanationText.setVisibility(VISIBLE);
+ translationY = mDots.getBottom() - mTextPaddingInset;
+ scale = 1.0f;
+ alpha = 1.0f;
+ needsHideListener = false;
+ }
+ mExplanationText.animate().setInterpolator(mFastOutSlowInInterpolator)
+ .alpha(alpha)
+ .scaleX(scale)
+ .scaleY(scale)
+ .translationY(translationY)
+ .setListener(needsHideListener ? mHideExplanationListener : null)
+ .withLayer();
+ mExplanationTextVisible = visible;
+ }
+ }
+
+ @Override
+ public boolean isTransparent() {
+ return true;
+ }
+
+ public void performVisibilityAnimation(boolean nowVisible) {
+ animateDivider(nowVisible);
+
+ // Animate explanation Text
+ if (mIsExpanded) {
+ animateExplanationTextInternal(nowVisible);
+ }
+ }
+
+ public void animateDivider(boolean nowVisible) {
+ if (nowVisible != mDividerVisible) {
+ // Animate dividers
+ float endValue = nowVisible ? 1.0f : 0.0f;
+ float endTranslationXLeft = nowVisible ? 0.0f : mCenterX - mLineLeft.getRight();
+ float endTranslationXRight = nowVisible ? 0.0f : mCenterX - mLineRight.getLeft();
+ mLineLeft.animate()
+ .alpha(endValue)
+ .withLayer()
+ .scaleX(endValue)
+ .scaleY(endValue)
+ .translationX(endTranslationXLeft)
+ .setInterpolator(mFastOutSlowInInterpolator);
+ mLineRight.animate()
+ .alpha(endValue)
+ .withLayer()
+ .scaleX(endValue)
+ .scaleY(endValue)
+ .translationX(endTranslationXRight)
+ .setInterpolator(mFastOutSlowInInterpolator);
+
+ // Animate dots
+ mDots.performVisibilityAnimation(nowVisible);
+ mDividerVisible = nowVisible;
+ }
+ }
+
+ public void setInvisible() {
+ float endTranslationXLeft = mCenterX - mLineLeft.getRight();
+ float endTranslationXRight = mCenterX - mLineRight.getLeft();
+ mLineLeft.setAlpha(0.0f);
+ mLineLeft.setScaleX(0.0f);
+ mLineLeft.setScaleY(0.0f);
+ mLineLeft.setTranslationX(endTranslationXLeft);
+ mLineRight.setAlpha(0.0f);
+ mLineRight.setScaleX(0.0f);
+ mLineRight.setScaleY(0.0f);
+ mLineRight.setTranslationX(endTranslationXRight);
+ mDots.setInvisible();
+ resetExplanationText();
+
+ mDividerVisible = false;
+ }
+
+ public void collapse() {
+ if (mIsExpanded) {
+ setActualHeight(mCollapsedHeight);
+ mIsExpanded = false;
+ }
+ resetExplanationText();
+ }
+
+ public void animateExplanationText(boolean nowVisible) {
+ if (mIsExpanded) {
+ animateExplanationTextInternal(nowVisible);
+ }
+ }
+
+ private void resetExplanationText() {
+ mExplanationText.setTranslationY(0);
+ mExplanationText.setVisibility(INVISIBLE);
+ mExplanationText.setAlpha(0.0f);
+ mExplanationText.setScaleX(0.5f);
+ mExplanationText.setScaleY(0.5f);
+ mExplanationTextVisible = false;
+ }
+
+ public boolean isExpanded() {
+ return mIsExpanded;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 869edff..0a3fdef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -60,7 +60,8 @@
} else if (mDemoMode && command.equals(COMMAND_STATUS)) {
String volume = args.getString("volume");
if (volume != null) {
- int iconId = volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
+ int iconId = volume.equals("zen") ? R.drawable.stat_sys_ringer_zen
+ : volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
: volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate
: 0;
updateSlot("volume", null, iconId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b9f5ab2..19252c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -18,6 +18,8 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
@@ -25,6 +27,7 @@
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -36,12 +39,11 @@
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener {
- public static final boolean DEBUG_GESTURES = true;
- private static final int EXPANSION_ANIMATION_LENGTH = 375;
PhoneStatusBar mStatusBar;
private StatusBarHeaderView mHeader;
@@ -80,6 +82,20 @@
private FlingAnimationUtils mFlingAnimationUtils;
private int mStatusBarMinHeight;
+ private int mClockNotificationsMarginMin;
+ private int mClockNotificationsMarginMax;
+ private float mClockYFractionMin;
+ private float mClockYFractionMax;
+ private Interpolator mFastOutSlowInInterpolator;
+ private ObjectAnimator mClockAnimator;
+ private int mClockAnimationTarget = -1;
+
+ /**
+ * The number (fractional) of notifications the "more" card counts when calculating how many
+ * notifications are currently visible for the y positioning of the clock.
+ */
+ private float mMoreCardNotificationAmount;
+
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -113,9 +129,27 @@
mNotificationStackScroller = (NotificationStackScrollLayout)
findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+ android.R.interpolator.fast_out_slow_in);
+ }
+
+ @Override
+ protected void loadDimens() {
+ super.loadDimens();
mNotificationTopPadding = getResources().getDimensionPixelSize(
R.dimen.notifications_top_padding);
mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
+ mClockNotificationsMarginMin = getResources().getDimensionPixelSize(
+ R.dimen.keyguard_clock_notifications_margin_min);
+ mClockNotificationsMarginMax = getResources().getDimensionPixelSize(
+ R.dimen.keyguard_clock_notifications_margin_max);
+ mClockYFractionMin =
+ getResources().getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1);
+ mClockYFractionMax =
+ getResources().getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1);
+ mMoreCardNotificationAmount =
+ (float) getResources().getDimensionPixelSize(R.dimen.notification_summary_height) /
+ getResources().getDimensionPixelSize(R.dimen.notification_min_height);
mFlingAnimationUtils = new FlingAnimationUtils(getContext());
mStatusBarMinHeight = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
@@ -124,15 +158,8 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- int keyguardBottomMargin =
- ((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
if (!mQsExpanded) {
- mStackScrollerIntrinsicPadding = mStatusBar.getBarState() == StatusBarState.KEYGUARD
- ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
- : mHeader.getBottom() + mNotificationTopPadding;
- mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
- mAnimateNextTopPaddingChange);
- mAnimateNextTopPaddingChange = false;
+ positionClockAndNotifications();
}
// Calculate quick setting heights.
@@ -143,8 +170,81 @@
}
}
- public void animateNextTopPaddingChange() {
+ /**
+ * Positions the clock and notifications dynamically depending on how many notifications are
+ * showing.
+ */
+ private void positionClockAndNotifications() {
+ boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
+ if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
+ mStackScrollerIntrinsicPadding = mHeader.getBottom() + mNotificationTopPadding;
+ } else {
+ int notificationCount = mNotificationStackScroller.getNotGoneChildCount();
+ int y = getClockY(notificationCount) - mKeyguardStatusView.getHeight()/2;
+ int padding = getClockNotificationsPadding(notificationCount);
+ if (animateClock || mClockAnimator != null) {
+ startClockAnimation(y);
+ } else {
+ mKeyguardStatusView.setY(y);
+ }
+ mStackScrollerIntrinsicPadding = y + mKeyguardStatusView.getHeight() + padding;
+ }
+ mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
+ mAnimateNextTopPaddingChange || animateClock);
+ mAnimateNextTopPaddingChange = false;
+ }
+
+ private void startClockAnimation(int y) {
+ if (mClockAnimationTarget == y) {
+ return;
+ }
+ mClockAnimationTarget = y;
+ getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ if (mClockAnimator != null) {
+ mClockAnimator.removeAllListeners();
+ mClockAnimator.cancel();
+ }
+ mClockAnimator =
+ ObjectAnimator.ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
+ mClockAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ mClockAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mClockAnimator = null;
+ mClockAnimationTarget = -1;
+ }
+ });
+ StackStateAnimator.startInstantly(mClockAnimator);
+ return true;
+ }
+ });
+ }
+
+ private int getClockNotificationsPadding(int notificationCount) {
+ float t = notificationCount
+ / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount);
+ t = Math.min(t, 1.0f);
+ return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax);
+ }
+
+ private float getClockYFraction(int notificationCount) {
+ float t = notificationCount
+ / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount);
+ t = Math.min(t, 1.0f);
+ return (1 - t) * mClockYFractionMax + t * mClockYFractionMin;
+ }
+
+ private int getClockY(int notificationCount) {
+ return (int) (getClockYFraction(notificationCount) * getHeight());
+ }
+
+ public void animateToFullShade() {
mAnimateNextTopPaddingChange = true;
+ mNotificationStackScroller.goToFullShade();
requestLayout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 8c70517..517f763 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -20,6 +20,7 @@
import android.animation.TimeAnimator;
import android.animation.TimeAnimator.TimeListener;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.util.Log;
@@ -218,7 +219,7 @@
};
private float mVel, mAccel;
- protected int mMaxPanelHeight = 0;
+ protected int mMaxPanelHeight = -1;
private String mViewName;
private float mInitialTouchY;
private float mInitialTouchX;
@@ -321,7 +322,7 @@
setOnHierarchyChangeListener(mHierarchyListener);
}
- private void loadDimens() {
+ protected void loadDimens() {
final Resources res = getContext().getResources();
mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
@@ -582,10 +583,16 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
loadDimens();
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ loadDimens();
+ mMaxPanelHeight = -1;
+ }
+
public void fling(float vel, boolean always) {
if (DEBUG) logf("fling: vel=%.3f, this=%s", vel, this);
mVel = vel;
@@ -617,7 +624,8 @@
// Did one of our children change size?
int newHeight = getMeasuredHeight();
- if (newHeight != mMaxPanelHeight) {
+ if (newHeight > mMaxPanelHeight) {
+ // we only adapt the max height if it's bigger
mMaxPanelHeight = newHeight;
// If the user isn't actively poking us, let's rubberband to the content
if (!mTracking && !mTimeAnimator.isStarted()
@@ -706,6 +714,7 @@
* @return the default implementation simply returns the maximum height.
*/
protected int getMaxPanelHeight() {
+ mMaxPanelHeight = Math.max(mMaxPanelHeight, getHeight());
return mMaxPanelHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d3b5f96..1072e49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -106,6 +106,7 @@
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -222,8 +223,6 @@
IconMerger mNotificationIcons;
// [+>
View mMoreIcon;
- // mode indicator icon
- ImageView mModeIcon;
// expanded notifications
NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -487,13 +486,14 @@
@Override
public void setZenMode(int mode) {
super.setZenMode(mode);
- if (mModeIcon == null) return;
if (!isDeviceProvisioned()) return;
final boolean zen = mode != Settings.Global.ZEN_MODE_OFF;
- mModeIcon.setVisibility(zen ? View.VISIBLE : View.GONE);
if (!zen) {
mIntercepted.releaseIntercepted();
}
+ if (mIconPolicy != null) {
+ mIconPolicy.setZenMode(zen);
+ }
}
@Override
@@ -617,8 +617,6 @@
mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
mNotificationIcons.setOverflowIndicator(mMoreIcon);
- mModeIcon = (ImageView)mStatusBarView.findViewById(R.id.modeIcon);
- mModeIcon.setImageResource(R.drawable.stat_sys_zen_limited);
mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
mTickerView = mStatusBarView.findViewById(R.id.ticker);
@@ -634,6 +632,10 @@
mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
mStackScroller.addView(mKeyguardIconOverflowContainer);
+ SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_notification_speed_bump, mStackScroller, false);
+ mStackScroller.setSpeedBumpView(speedBump);
+
mExpandedContents = mStackScroller;
mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
@@ -1150,7 +1152,7 @@
ArrayList<View> toRemove = new ArrayList<View>();
for (int i=0; i< mStackScroller.getChildCount(); i++) {
View child = mStackScroller.getChildAt(i);
- if (!toShow.contains(child) && child != mKeyguardIconOverflowContainer) {
+ if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
toRemove.add(child);
}
}
@@ -1391,8 +1393,8 @@
if ((state & StatusBarManager.DISABLE_RECENT) != 0) {
// close recents if it's visible
- mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+ mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
+ mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
}
}
@@ -1543,8 +1545,8 @@
}
if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
- mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
- mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+ mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
+ mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
}
if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
@@ -2560,13 +2562,13 @@
|| (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
}
- public void postStartSettingsActivity(final Intent intent) {
- mHandler.post(new Runnable() {
+ public void postStartSettingsActivity(final Intent intent, int delay) {
+ mHandler.postDelayed(new Runnable() {
@Override
public void run() {
handleStartSettingsActivity(intent, true /*onlyProvisioned*/);
}
- });
+ }, delay);
}
private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
@@ -2582,7 +2584,7 @@
}
public void startSettingsActivity(String action) {
- postStartSettingsActivity(new Intent(action));
+ postStartSettingsActivity(new Intent(action), 0);
}
private static class FastColorDrawable extends Drawable {
@@ -2722,7 +2724,7 @@
setBarState(StatusBarState.SHADE);
if (mLeaveOpenOnKeyguardHide) {
mLeaveOpenOnKeyguardHide = false;
- mNotificationPanel.animateNextTopPaddingChange();
+ mNotificationPanel.animateToFullShade();
} else {
instantCollapseNotificationPanel();
}
@@ -2894,7 +2896,7 @@
mLeaveOpenOnKeyguardHide = true;
showBouncer();
} else {
- mNotificationPanel.animateNextTopPaddingChange();
+ mNotificationPanel.animateToFullShade();
setBarState(StatusBarState.SHADE_LOCKED);
updateKeyguardState();
}
@@ -2917,4 +2919,12 @@
public void reattachSystemIcons() {
mSystemIconArea.addView(mSystemIcons, 0);
}
+
+ public void onScreenTurnedOff() {
+ mStackScroller.setAnimationsEnabled(false);
+ }
+
+ public void onScreenTurnedOn() {
+ mStackScroller.setAnimationsEnabled(true);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 194774d..b6f5ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -63,6 +63,9 @@
// ringer volume
private boolean mVolumeVisible;
+ // zen mode
+ private boolean mZen;
+
// bluetooth device status
private boolean mBluetoothEnabled = false;
@@ -152,6 +155,11 @@
updateVolume();
}
+ public void setZenMode(boolean zen) {
+ mZen = zen;
+ updateVolume();
+ }
+
private final void updateAlarm(Intent intent) {
boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
mService.setIconVisibility("alarm_clock", alarmSet);
@@ -195,11 +203,15 @@
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
final int ringerMode = audioManager.getRingerMode();
final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
- ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+ ringerMode == AudioManager.RINGER_MODE_VIBRATE ||
+ mZen;
final int iconId;
String contentDescription = null;
- if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ if (mZen) {
+ iconId = R.drawable.stat_sys_ringer_zen;
+ contentDescription = mContext.getString(R.string.zen_mode_title);
+ } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
iconId = R.drawable.stat_sys_ringer_vibrate;
contentDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 1fe3be5..7029898 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.VectorDrawable;
import android.os.HandlerThread;
import android.os.Looper;
@@ -113,7 +112,7 @@
@Override
public void startSettingsActivity(final Intent intent) {
- mStatusBar.postStartSettingsActivity(intent);
+ mStatusBar.postStartSettingsActivity(intent, QSTile.FEEDBACK_START_DELAY);
}
@Override
@@ -137,11 +136,6 @@
}
@Override
- public VectorDrawable getVectorDrawable(int resId) {
- return (VectorDrawable) mContext.getDrawable(resId);
- }
-
- @Override
public BluetoothController getBluetoothController() {
return mBluetooth;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 2305445..36b063b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -86,6 +86,7 @@
(ImageView) findViewById(R.id.brightness_icon),
(ToggleSlider) findViewById(R.id.brightness_slider));
loadDimens();
+ updateVisibilities();
}
private void loadDimens() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 77b760e..1040c15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -125,11 +125,13 @@
public void onScreenTurnedOff() {
mScreenOn = false;
+ mPhoneStatusBar.onScreenTurnedOff();
mBouncer.onScreenTurnedOff();
}
public void onScreenTurnedOn(final IKeyguardShowCallback callback) {
mScreenOn = true;
+ mPhoneStatusBar.onScreenTurnedOn();
if (callback != null) {
callbackAfterDraw(callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 1c7119f..5a19881 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -59,6 +59,7 @@
public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
mChangeCallbacks.add(cb);
+ fireCallback(cb);
}
@Override
@@ -131,7 +132,11 @@
private void fireCallbacks() {
for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
- cb.onBluetoothStateChange(mEnabled);
+ fireCallback(cb);
}
}
+
+ private void fireCallback(BluetoothStateChangeCallback cb) {
+ cb.onBluetoothStateChange(mEnabled);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index 33a85b1..bcd865c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -28,6 +28,10 @@
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final MediaRouter mMediaRouter;
+ private boolean mEnabled;
+ private boolean mConnecting;
+ private String mConnectedRouteName;
+
public CastControllerImpl(Context context) {
mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
}
@@ -35,6 +39,7 @@
@Override
public void addCallback(Callback callback) {
mCallbacks.add(callback);
+ fireStateChanged(callback);
}
@Override
@@ -76,12 +81,23 @@
if (connectedRoute != null) {
connectedRouteName = connectedRoute.getName().toString();
}
- fireStateChanged(enabled, connecting, connectedRouteName);
+ synchronized(mCallbacks) {
+ mEnabled = enabled;
+ mConnecting = connecting;
+ mConnectedRouteName = connectedRouteName;
+ }
+ fireStateChanged();
}
- private void fireStateChanged(boolean enabled, boolean connecting, String connectedRouteName) {
+ private void fireStateChanged() {
for (Callback callback : mCallbacks) {
- callback.onStateChanged(enabled, connecting, connectedRouteName);
+ fireStateChanged(callback);
+ }
+ }
+
+ private void fireStateChanged(Callback callback) {
+ synchronized(mCallbacks) {
+ callback.onStateChanged(mEnabled, mConnecting, mConnectedRouteName);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Listenable.java
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/Listenable.java
index 158e9c1..4fa59fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Listenable.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.policy;
-/** Common interface for items requiring manual cleanup. **/
-public interface Disposable {
- void dispose();
+/** Common interface for components with an active listening state. **/
+public interface Listenable {
+ void setListening(boolean listening);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 9e5ad18..d5b2548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -92,6 +92,7 @@
*/
public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
mSettingsChangeCallbacks.add(cb);
+ locationSettingsChanged(cb);
}
public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
@@ -204,6 +205,10 @@
}
}
+ private void locationSettingsChanged(LocationSettingsChangeCallback cb) {
+ cb.onLocationSettingsChanged(isLocationEnabled());
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 1eb678d..93c4691 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.policy;
-public interface RotationLockController extends Disposable {
+public interface RotationLockController extends Listenable {
int getRotationLockOrientation();
boolean isRotationLockAffordanceVisible();
boolean isRotationLocked();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index caa07ef..c3bcd94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -39,12 +39,12 @@
public RotationLockControllerImpl(Context context) {
mContext = context;
- RotationPolicy.registerRotationPolicyListener(mContext,
- mRotationPolicyListener, UserHandle.USER_ALL);
+ setListening(true);
}
public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
mCallbacks.add(callback);
+ notifyChanged(callback);
}
public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) {
@@ -68,14 +68,23 @@
}
@Override
- public void dispose() {
- RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+ public void setListening(boolean listening) {
+ if (listening) {
+ RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
+ UserHandle.USER_ALL);
+ } else {
+ RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+ }
}
private void notifyChanged() {
for (RotationLockControllerCallback callback : mCallbacks) {
- callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
- RotationPolicy.isRotationLockToggleVisible(mContext));
+ notifyChanged(callback);
}
}
+
+ private void notifyChanged(RotationLockControllerCallback callback) {
+ callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
+ RotationPolicy.isRotationLockToggleVisible(mContext));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index d760f78..adf2935 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -52,6 +52,7 @@
fireZenChanged(value != 0);
}
};
+ mSetting.setListening(true);
mNoMan = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index deab757..b21e12c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -30,6 +30,7 @@
private View mActivatedChild;
private float mOverScrollTopAmount;
private float mOverScrollBottomAmount;
+ private int mSpeedBumpIndex = -1;
public int getScrollY() {
return mScrollY;
@@ -86,4 +87,12 @@
public float getOverScrollAmount(boolean top) {
return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
}
+
+ public int getSpeedBumpIndex() {
+ return mSpeedBumpIndex;
+ }
+
+ public void setSpeedBumpIndex(int speedBumpIndex) {
+ mSpeedBumpIndex = speedBumpIndex;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index fbb6695..58ada75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -39,6 +39,7 @@
import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
import com.android.systemui.statusbar.policy.ScrollAdapter;
@@ -107,6 +108,7 @@
= new ArrayList<AnimationEvent>();
private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
+ private boolean mAnimationsEnabled;
/**
* The raw amount of the overScroll on the top, which is not rubber-banded.
@@ -126,6 +128,8 @@
private boolean mActivateNeedsAnimation;
private boolean mIsExpanded = true;
private boolean mChildrenUpdateRequested;
+ private SpeedBumpView mSpeedBumpView;
+ private boolean mIsExpansionChanging;
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -244,6 +248,22 @@
requestChildrenUpdate();
}
+ public void updateSpeedBumpIndex(int newIndex) {
+ int currentIndex = indexOfChild(mSpeedBumpView);
+
+ // If we are currently layouted before the new speed bump index, we have to decrease it.
+ boolean validIndex = newIndex > 0;
+ if (newIndex > getChildCount() - 1) {
+ validIndex = false;
+ newIndex = -1;
+ }
+ if (validIndex && currentIndex != newIndex) {
+ changeViewPosition(mSpeedBumpView, newIndex);
+ }
+ updateSpeedBump(validIndex);
+ mAmbientState.setSpeedBumpIndex(newIndex);
+ }
+
public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
mListener = listener;
}
@@ -333,7 +353,7 @@
mTopPadding = topPadding;
updateAlgorithmHeightAndPadding();
updateContentHeight();
- if (animate) {
+ if (animate && mAnimationsEnabled && mIsExpanded) {
mTopPaddingNeedsAnimation = true;
mNeedsAnimation = true;
}
@@ -421,9 +441,11 @@
public void onChildSnappedBack(View animView) {
mAmbientState.onDragFinished(animView);
if (!mDragAnimPendingChildren.contains(animView)) {
- mSnappedBackChildren.add(animView);
+ if (mAnimationsEnabled) {
+ mSnappedBackChildren.add(animView);
+ mNeedsAnimation = true;
+ }
requestChildrenUpdate();
- mNeedsAnimation = true;
} else {
// We start the swipe and snap back in the same frame, we don't want any animation
mDragAnimPendingChildren.remove(animView);
@@ -432,10 +454,12 @@
public void onBeginDrag(View v) {
setSwipingInProgress(true);
- mDragAnimPendingChildren.add(v);
mAmbientState.onBeginDrag(v);
+ if (mAnimationsEnabled) {
+ mDragAnimPendingChildren.add(v);
+ mNeedsAnimation = true;
+ }
requestChildrenUpdate();
- mNeedsAnimation = true;
}
public void onDragCancelled(View v) {
@@ -942,6 +966,21 @@
return null;
}
+ /**
+ * @return the number of children which have visibility unequal to GONE
+ */
+ public int getNotGoneChildCount() {
+ int childCount = getChildCount();
+ int count = 0;
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ count++;
+ }
+ }
+ return count;
+ }
+
private int getMaxExpandHeight(View view) {
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
@@ -1044,8 +1083,11 @@
mCurrentStackScrollState.removeViewStateForView(child);
mStackScrollAlgorithm.notifyChildrenChanged(this);
updateScrollStateForRemovedChild(child);
- if (mIsExpanded) {
+ generateRemoveAnimation(child);
+ }
+ private void generateRemoveAnimation(View child) {
+ if (mIsExpanded && mAnimationsEnabled) {
if (!mChildrenToAddAnimated.contains(child)) {
// Generate Animations
mChildrenToRemoveAnimated.add(child);
@@ -1103,8 +1145,17 @@
}
}
+ public void setAnimationsEnabled(boolean animationsEnabled) {
+ mAnimationsEnabled = animationsEnabled;
+ }
+
+ public boolean isAddOrRemoveAnimationPending() {
+ return mNeedsAnimation
+ && (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty());
+ }
+
public void generateAddAnimation(View child) {
- if (mIsExpanded) {
+ if (mIsExpanded && mAnimationsEnabled) {
// Generate Animations
mChildrenToAddAnimated.add(child);
@@ -1120,7 +1171,9 @@
*/
public void changeViewPosition(View child, int newIndex) {
if (child != null && child.getParent() == this) {
- // TODO: handle this
+ removeView(child);
+ addView(child, newIndex);
+ // TODO: handle events
}
}
@@ -1362,10 +1415,12 @@
}
public void onExpansionStarted() {
+ mIsExpansionChanging = true;
mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
}
public void onExpansionStopped() {
+ mIsExpansionChanging = false;
mStackScrollAlgorithm.onExpansionStopped();
}
@@ -1374,6 +1429,7 @@
mStackScrollAlgorithm.setIsExpanded(isExpanded);
if (!isExpanded) {
mOwnScrollY = 0;
+ mSpeedBumpView.collapse();
}
}
@@ -1404,7 +1460,7 @@
mStackScrollAlgorithm.setDimmed(dimmed);
mAmbientState.setDimmed(dimmed);
updatePadding(dimmed);
- if (animate) {
+ if (animate && mAnimationsEnabled) {
mDimmedNeedsAnimation = true;
mNeedsAnimation = true;
}
@@ -1416,8 +1472,10 @@
*/
public void setActivatedChild(View activatedChild) {
mAmbientState.setActivatedChild(activatedChild);
- mActivateNeedsAnimation = true;
- mNeedsAnimation = true;
+ if (mAnimationsEnabled) {
+ mActivateNeedsAnimation = true;
+ mNeedsAnimation = true;
+ }
requestChildrenUpdate();
}
@@ -1432,6 +1490,34 @@
}
}
+ public void setSpeedBumpView(SpeedBumpView speedBumpView) {
+ mSpeedBumpView = speedBumpView;
+ addView(speedBumpView);
+ }
+
+ private void updateSpeedBump(boolean visible) {
+ int newVisibility = visible ? VISIBLE : GONE;
+ int oldVisibility = mSpeedBumpView.getVisibility();
+ if (newVisibility != oldVisibility) {
+ mSpeedBumpView.setVisibility(newVisibility);
+ if (visible) {
+ mSpeedBumpView.collapse();
+ // Make invisible to ensure that the appear animation is played.
+ mSpeedBumpView.setInvisible();
+ if (!mIsExpansionChanging) {
+ generateAddAnimation(mSpeedBumpView);
+ }
+ } else {
+ mSpeedBumpView.performVisibilityAnimation(false);
+ generateRemoveAnimation(mSpeedBumpView);
+ }
+ }
+ }
+
+ public void goToFullShade() {
+ updateSpeedBump(true);
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 8fc26d8..011411c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -23,6 +23,7 @@
import android.view.ViewGroup;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.SpeedBumpView;
import java.util.HashMap;
import java.util.Map;
@@ -167,13 +168,50 @@
clipHeight,
(int) (newHeight - (previousNotificationStart - newYTranslation)));
- previousNotificationStart = newYTranslation + child.getClipTopAmount();
- previousNotificationEnd = newNotificationEnd;
- previousNotificationIsSwiped = child.getTranslationX() != 0;
+ if (!child.isTransparent()) {
+ // Only update the previous values if we are not transparent,
+ // otherwise we would clip to a transparent view.
+ previousNotificationStart = newYTranslation + child.getClipTopAmount();
+ previousNotificationEnd = newNotificationEnd;
+ previousNotificationIsSwiped = child.getTranslationX() != 0;
+ }
+
+ if(child instanceof SpeedBumpView) {
+ performSpeedBumpAnimation(i, (SpeedBumpView) child, newNotificationEnd,
+ newYTranslation);
+ }
}
}
}
+ private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
+ float speedBumpStart) {
+ View nextChild = getNextChildNotGone(i);
+ if (nextChild != null) {
+ ViewState nextState = getViewStateForView(nextChild);
+ boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
+ speedBump.animateDivider(startIsAboveNext);
+
+ // handle expanded case
+ if (speedBump.isExpanded()) {
+ boolean endIsAboveNext = nextState.yTranslation > speedBumpEnd;
+ speedBump.animateExplanationText(endIsAboveNext);
+ }
+
+ }
+ }
+
+ private View getNextChildNotGone(int childIndex) {
+ int childCount = mHostView.getChildCount();
+ for (int i = childIndex + 1; i < childCount; i++) {
+ View child = mHostView.getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ return child;
+ }
+ }
+ return null;
+ }
+
/**
* Updates the shadow outline and the clipping for a view.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 5ac51f8..a9dcdd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -434,7 +434,7 @@
/**
* Start an animator instantly instead of waiting on the next synchronization frame
*/
- private void startInstantly(ValueAnimator animator) {
+ public static void startInstantly(ValueAnimator animator) {
animator.start();
animator.setCurrentPlayTime(0);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 1b96f1f..2fea785 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -36,6 +36,7 @@
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarOverlayLayout;
import com.android.internal.widget.ActionBarView;
+import com.android.internal.widget.DecorContentParent;
import com.android.internal.widget.SwipeDismissLayout;
import android.app.ActivityManager;
@@ -147,7 +148,7 @@
private TextView mTitleView;
- private ActionBarView mActionBar;
+ private DecorContentParent mDecorContentParent;
private ActionMenuPresenterCallback mActionMenuPresenterCallback;
private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
@@ -204,6 +205,8 @@
private int mTextColor = 0;
private int mStatusBarColor = 0;
private int mNavigationBarColor = 0;
+ private boolean mForcedStatusBarColor = false;
+ private boolean mForcedNavigationBarColor = false;
private CharSequence mTitle = null;
@@ -439,8 +442,8 @@
public void setTitle(CharSequence title) {
if (mTitleView != null) {
mTitleView.setText(title);
- } else if (mActionBar != null) {
- mActionBar.setWindowTitle(title);
+ } else if (mDecorContentParent != null) {
+ mDecorContentParent.setWindowTitle(title);
}
mTitle = title;
}
@@ -487,10 +490,10 @@
final boolean isActionBarMenu =
(st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
- if (isActionBarMenu && mActionBar != null) {
+ if (isActionBarMenu && mDecorContentParent != null) {
// Enforce ordering guarantees around events so that the action bar never
// dispatches menu-related events before the panel is prepared.
- mActionBar.setMenuPrepared();
+ mDecorContentParent.setMenuPrepared();
}
if (st.createdPanelView == null) {
@@ -502,11 +505,11 @@
}
}
- if (isActionBarMenu && mActionBar != null) {
+ if (isActionBarMenu && mDecorContentParent != null) {
if (mActionMenuPresenterCallback == null) {
mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
}
- mActionBar.setMenu(st.menu, mActionMenuPresenterCallback);
+ mDecorContentParent.setMenu(st.menu, mActionMenuPresenterCallback);
}
// Call callback, and return if it doesn't want to display menu.
@@ -518,9 +521,9 @@
// Ditch the menu created above
st.setMenu(null);
- if (isActionBarMenu && mActionBar != null) {
+ if (isActionBarMenu && mDecorContentParent != null) {
// Don't show it in the action bar either
- mActionBar.setMenu(null, mActionMenuPresenterCallback);
+ mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
}
return false;
@@ -543,10 +546,10 @@
}
if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
- if (isActionBarMenu && mActionBar != null) {
+ if (isActionBarMenu && mDecorContentParent != null) {
// The app didn't want to show the menu for now but it still exists.
// Clear it out of the action bar.
- mActionBar.setMenu(null, mActionMenuPresenterCallback);
+ mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
}
st.menu.startDispatchingItemsChanged();
return false;
@@ -571,7 +574,7 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
// Action bars handle their own menu state
- if (mActionBar == null) {
+ if (mDecorContentParent == null) {
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if ((st != null) && (st.menu != null)) {
if (st.isOpen) {
@@ -623,12 +626,10 @@
@Override
public final void openPanel(int featureId, KeyEvent event) {
- if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
- mActionBar.isOverflowReserved() &&
+ if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+ mDecorContentParent.canShowOverflowMenu() &&
!ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
- if (mActionBar.getVisibility() == View.VISIBLE) {
- mActionBar.showOverflowMenu();
- }
+ mDecorContentParent.showOverflowMenu();
} else {
openPanel(getPanelState(featureId, true), event);
}
@@ -757,10 +758,10 @@
@Override
public final void closePanel(int featureId) {
- if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
- mActionBar.isOverflowReserved() &&
+ if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+ mDecorContentParent.canShowOverflowMenu() &&
!ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
- mActionBar.hideOverflowMenu();
+ mDecorContentParent.hideOverflowMenu();
} else if (featureId == FEATURE_CONTEXT_MENU) {
closeContextMenu();
} else {
@@ -782,7 +783,7 @@
public final void closePanel(PanelFeatureState st, boolean doCallback) {
// System.out.println("Close panel: isOpen=" + st.isOpen);
if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL &&
- mActionBar != null && mActionBar.isOverflowMenuShowing()) {
+ mDecorContentParent != null && mDecorContentParent.isOverflowMenuShowing()) {
checkCloseActionMenu(st.menu);
return;
}
@@ -828,7 +829,7 @@
}
mClosingActionMenu = true;
- mActionBar.dismissPopupMenus();
+ mDecorContentParent.dismissPopups();
Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
@@ -874,7 +875,7 @@
// Prepare the options panel if we have an action bar
if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
- && mActionBar != null) {
+ && mDecorContentParent != null) {
st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
if (st != null) {
st.isPrepared = false;
@@ -921,17 +922,15 @@
boolean playSoundEffect = false;
final PanelFeatureState st = getPanelState(featureId, true);
- if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
- mActionBar.isOverflowReserved() &&
+ if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+ mDecorContentParent.canShowOverflowMenu() &&
!ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
- if (mActionBar.getVisibility() == View.VISIBLE) {
- if (!mActionBar.isOverflowMenuShowing()) {
- if (!isDestroyed() && preparePanel(st, event)) {
- playSoundEffect = mActionBar.showOverflowMenu();
- }
- } else {
- playSoundEffect = mActionBar.hideOverflowMenu();
+ if (!mDecorContentParent.isOverflowMenuShowing()) {
+ if (!isDestroyed() && preparePanel(st, event)) {
+ playSoundEffect = mDecorContentParent.showOverflowMenu();
}
+ } else {
+ playSoundEffect = mDecorContentParent.hideOverflowMenu();
}
} else {
if (st.isOpen || st.isHandled) {
@@ -1044,7 +1043,7 @@
st.isHandled = true;
// Only close down the menu if we don't have an action bar keeping it open.
- if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mActionBar == null) {
+ if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mDecorContentParent == null) {
closePanel(st, true);
}
}
@@ -1066,7 +1065,7 @@
boolean res = st.menu.performIdentifierAction(id, flags);
// Only close down the menu if we don't have an action bar keeping it open.
- if (mActionBar == null) {
+ if (mDecorContentParent == null) {
closePanel(st, true);
}
@@ -1101,12 +1100,12 @@
}
private void reopenMenu(boolean toggleMenuMode) {
- if (mActionBar != null && mActionBar.isOverflowReserved() &&
+ if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() &&
(!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
- mActionBar.isOverflowMenuShowPending())) {
+ mDecorContentParent.isOverflowMenuShowPending())) {
final Callback cb = getCallback();
- if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
- if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) {
+ if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) {
+ if (cb != null && !isDestroyed()) {
// If we have a menu invalidation pending, do it now.
if (mInvalidatePanelMenuPosted &&
(mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
@@ -1121,11 +1120,11 @@
if (st.menu != null && !st.refreshMenuContent &&
cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
- mActionBar.showOverflowMenu();
+ mDecorContentParent.showOverflowMenu();
}
}
} else {
- mActionBar.hideOverflowMenu();
+ mDecorContentParent.hideOverflowMenu();
if (cb != null && !isDestroyed()) {
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
@@ -1162,7 +1161,7 @@
// If we have an action bar, initialize the menu with a context themed for it.
if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) &&
- mActionBar != null) {
+ mDecorContentParent != null) {
TypedValue outValue = new TypedValue();
Resources.Theme currentTheme = context.getTheme();
currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
@@ -1507,8 +1506,8 @@
mIconRes = resId;
mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
- if (mActionBar != null) {
- mActionBar.setIcon(resId);
+ if (mDecorContentParent != null) {
+ mDecorContentParent.setIcon(resId);
}
}
@@ -1518,13 +1517,14 @@
return;
}
mIconRes = resId;
- if (mActionBar != null && (!mActionBar.hasIcon() ||
+ if (mDecorContentParent != null && (!mDecorContentParent.hasIcon() ||
(mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) {
if (resId != 0) {
- mActionBar.setIcon(resId);
+ mDecorContentParent.setIcon(resId);
mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
} else {
- mActionBar.setIcon(getContext().getPackageManager().getDefaultActivityIcon());
+ mDecorContentParent.setIcon(
+ getContext().getPackageManager().getDefaultActivityIcon());
mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
}
}
@@ -1534,8 +1534,8 @@
public void setLogo(int resId) {
mLogoRes = resId;
mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
- if (mActionBar != null) {
- mActionBar.setLogo(resId);
+ if (mDecorContentParent != null) {
+ mDecorContentParent.setLogo(resId);
}
}
@@ -1545,8 +1545,8 @@
return;
}
mLogoRes = resId;
- if (mActionBar != null && !mActionBar.hasLogo()) {
- mActionBar.setLogo(resId);
+ if (mDecorContentParent != null && !mDecorContentParent.hasLogo()) {
+ mDecorContentParent.setLogo(resId);
}
}
@@ -1803,9 +1803,9 @@
outState.putSparseParcelableArray(PANELS_TAG, panelStates);
}
- if (mActionBar != null) {
+ if (mDecorContentParent != null) {
SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
- mActionBar.saveHierarchyState(actionBarStates);
+ mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
}
@@ -1844,11 +1844,11 @@
restorePanelState(panelStates);
}
- if (mActionBar != null) {
+ if (mDecorContentParent != null) {
SparseArray<Parcelable> actionBarStates =
savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
if (actionBarStates != null) {
- mActionBar.restoreHierarchyState(actionBarStates);
+ mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
} else {
Log.w(TAG, "Missing saved instance states for action bar views! " +
"State will not be restored.");
@@ -2122,12 +2122,7 @@
}
public boolean superDispatchKeyEvent(KeyEvent event) {
- if (super.dispatchKeyEvent(event)) {
- return true;
- }
-
- // Not handled by the view hierarchy, does the action bar want it
- // to cancel out of something special?
+ // Give priority to closing action modes if applicable.
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
final int action = event.getAction();
// Back cancels action modes first.
@@ -2137,17 +2132,9 @@
}
return true;
}
-
- // Next collapse any expanded action views.
- if (mActionBar != null && mActionBar.hasExpandedActionView()) {
- if (action == KeyEvent.ACTION_UP) {
- mActionBar.collapseActionView();
- }
- return true;
- }
}
- return false;
+ return super.dispatchKeyEvent(event);
}
public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
@@ -2842,8 +2829,8 @@
cb.onDetachedFromWindow();
}
- if (mActionBar != null) {
- mActionBar.dismissPopupMenus();
+ if (mDecorContentParent != null) {
+ mDecorContentParent.dismissPopups();
}
if (mActionModePopup != null) {
@@ -3084,8 +3071,12 @@
}
decor.setOnSystemUiVisibilityChangeListener(decor);
}
- mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
- mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
+ if (!mForcedStatusBarColor) {
+ mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
+ }
+ if (!mForcedNavigationBarColor) {
+ mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
+ }
if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB) {
@@ -3275,96 +3266,68 @@
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
- mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
- if (mTitleView != null) {
- mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
- if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
- View titleContainer = findViewById(com.android.internal.R.id.title_container);
- if (titleContainer != null) {
- titleContainer.setVisibility(View.GONE);
- } else {
- mTitleView.setVisibility(View.GONE);
- }
- if (mContentParent instanceof FrameLayout) {
- ((FrameLayout)mContentParent).setForeground(null);
- }
- } else {
- mTitleView.setText(mTitle);
+ final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
+ com.android.internal.R.id.decor_content_parent);
+
+ if (decorContentParent != null) {
+ mDecorContentParent = decorContentParent;
+ mDecorContentParent.setWindowCallback(getCallback());
+ if (mDecorContentParent.getTitle() == null) {
+ mDecorContentParent.setWindowTitle(mTitle);
}
- } else {
- mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
- if (mActionBar != null) {
- mActionBar.setWindowCallback(getCallback());
- if (mActionBar.getTitle() == null) {
- mActionBar.setWindowTitle(mTitle);
- }
- final int localFeatures = getLocalFeatures();
- if ((localFeatures & (1 << FEATURE_PROGRESS)) != 0) {
- mActionBar.initProgress();
- }
- if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
- mActionBar.initIndeterminateProgress();
- }
- final ActionBarOverlayLayout abol = (ActionBarOverlayLayout) findViewById(
- com.android.internal.R.id.action_bar_overlay_layout);
- if (abol != null) {
- abol.setOverlayMode(
- (localFeatures & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0);
+ final int localFeatures = getLocalFeatures();
+ for (int i = 0; i < FEATURE_MAX; i++) {
+ if ((localFeatures & (1 << i)) != 0) {
+ mDecorContentParent.initFeature(i);
}
+ }
- boolean splitActionBar = false;
- final boolean splitWhenNarrow =
- (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
- if (splitWhenNarrow) {
- splitActionBar = getContext().getResources().getBoolean(
- com.android.internal.R.bool.split_action_bar_is_narrow);
- } else {
- splitActionBar = getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowSplitActionBar, false);
- }
- final ActionBarContainer splitView = (ActionBarContainer) findViewById(
- com.android.internal.R.id.split_action_bar);
- if (splitView != null) {
- mActionBar.setSplitView(splitView);
- mActionBar.setSplitActionBar(splitActionBar);
- mActionBar.setSplitWhenNarrow(splitWhenNarrow);
+ mDecorContentParent.setUiOptions(mUiOptions);
- final ActionBarContextView cab = (ActionBarContextView) findViewById(
- com.android.internal.R.id.action_context_bar);
- cab.setSplitView(splitView);
- cab.setSplitActionBar(splitActionBar);
- cab.setSplitWhenNarrow(splitWhenNarrow);
- } else if (splitActionBar) {
- Log.e(TAG, "Requested split action bar with " +
- "incompatible window decor! Ignoring request.");
- }
+ if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
+ (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
+ mDecorContentParent.setIcon(mIconRes);
+ } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
+ mIconRes == 0 && !mDecorContentParent.hasIcon()) {
+ mDecorContentParent.setIcon(
+ getContext().getPackageManager().getDefaultActivityIcon());
+ mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
+ }
+ if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
+ (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
+ mDecorContentParent.setLogo(mLogoRes);
+ }
- if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
- (mIconRes != 0 && !mActionBar.hasIcon())) {
- mActionBar.setIcon(mIconRes);
- } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
- mIconRes == 0 && !mActionBar.hasIcon()) {
- mActionBar.setIcon(
- getContext().getPackageManager().getDefaultActivityIcon());
- mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
- }
- if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
- (mLogoRes != 0 && !mActionBar.hasLogo())) {
- mActionBar.setLogo(mLogoRes);
- }
-
- // Post the panel invalidate for later; avoid application onCreateOptionsMenu
- // being called in the middle of onCreate or similar.
- mDecor.post(new Runnable() {
- public void run() {
- // Invalidate if the panel menu hasn't been created before this.
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
- if (!isDestroyed() && (st == null || st.menu == null)) {
- invalidatePanelMenu(FEATURE_ACTION_BAR);
- }
+ // Post the panel invalidate for later; avoid application onCreateOptionsMenu
+ // being called in the middle of onCreate or similar.
+ mDecor.post(new Runnable() {
+ public void run() {
+ // Invalidate if the panel menu hasn't been created before this.
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (!isDestroyed() && (st == null || st.menu == null)) {
+ invalidatePanelMenu(FEATURE_ACTION_BAR);
}
- });
+ }
+ });
+ } else {
+ mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
+ if (mTitleView != null) {
+ mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
+ if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
+ View titleContainer = findViewById(
+ com.android.internal.R.id.title_container);
+ if (titleContainer != null) {
+ titleContainer.setVisibility(View.GONE);
+ } else {
+ mTitleView.setVisibility(View.GONE);
+ }
+ if (mContentParent instanceof FrameLayout) {
+ ((FrameLayout)mContentParent).setForeground(null);
+ }
+ } else {
+ mTitleView.setText(mTitle);
+ }
}
}
@@ -4245,19 +4208,29 @@
@Override
public int getStatusBarColor() {
- return 0;
+ return mStatusBarColor;
}
@Override
public void setStatusBarColor(int color) {
+ mStatusBarColor = color;
+ mForcedStatusBarColor = true;
+ if (mDecor != null) {
+ mDecor.updateColorViews(null);
+ }
}
@Override
public int getNavigationBarColor() {
- return 0;
+ return mNavigationBarColor;
}
@Override
public void setNavigationBarColor(int color) {
+ mNavigationBarColor = color;
+ mForcedNavigationBarColor = true;
+ if (mDecor != null) {
+ mDecor.updateColorViews(null);
+ }
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8eed414..7c89d23 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -46,6 +46,7 @@
import android.media.IAudioService;
import android.media.Ringtone;
import android.media.RingtoneManager;
+import android.media.session.MediaSessionLegacyHelper;
import android.os.Bundle;
import android.os.FactoryTest;
import android.os.Handler;
@@ -137,6 +138,9 @@
static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
+ // Whether to use the new Session APIs
+ static final boolean USE_SESSIONS = true;
+
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -261,13 +265,7 @@
WindowState mLastInputMethodWindow = null;
WindowState mLastInputMethodTargetWindow = null;
- static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0;
- static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1;
- static final int RECENT_APPS_BEHAVIOR_DISMISS = 2;
- static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 3;
-
- RecentApplicationsDialog mRecentAppsDialog;
- int mRecentAppsDialogHeldModifiers;
+ int mRecentAppsHeldModifiers;
boolean mLanguageSwitchKeyPressed;
int mLidState = LID_ABSENT;
@@ -807,52 +805,6 @@
}
};
- /**
- * Create (if necessary) and show or dismiss the recent apps dialog according
- * according to the requested behavior.
- */
- void showOrHideRecentAppsDialog(final int behavior) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mRecentAppsDialog == null) {
- mRecentAppsDialog = new RecentApplicationsDialog(mContext);
- }
- if (mRecentAppsDialog.isShowing()) {
- switch (behavior) {
- case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
- case RECENT_APPS_BEHAVIOR_DISMISS:
- mRecentAppsDialog.dismiss();
- break;
- case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
- mRecentAppsDialog.dismissAndSwitch();
- break;
- case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
- default:
- break;
- }
- } else {
- switch (behavior) {
- case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS:
- mRecentAppsDialog.show();
- break;
- case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW:
- try {
- mWindowManager.setInTouchMode(false);
- } catch (RemoteException e) {
- }
- mRecentAppsDialog.show();
- break;
- case RECENT_APPS_BEHAVIOR_DISMISS:
- case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH:
- default:
- break;
- }
- }
- }
- });
- }
-
/** {@inheritDoc} */
@Override
public void init(Context context, IWindowManager windowManager,
@@ -1377,11 +1329,11 @@
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
}
-
+
void readLidState() {
mLidState = mWindowManagerFuncs.getLidState();
}
-
+
private boolean isHidden(int accessibilityMode) {
switch (accessibilityMode) {
case 1:
@@ -1728,16 +1680,16 @@
/**
* Preflight adding a window to the system.
- *
+ *
* Currently enforces that three window types are singletons:
* <ul>
* <li>STATUS_BAR_TYPE</li>
* <li>KEYGUARD_TYPE</li>
* </ul>
- *
+ *
* @param win The window to be added
* @param attrs Information about the window to be added
- *
+ *
* @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
* WindowManagerImpl.ADD_MULTIPLE_SINGLETON
*/
@@ -1810,7 +1762,7 @@
}
static final boolean PRINT_ANIM = false;
-
+
/** {@inheritDoc} */
@Override
public int selectAnimationLw(WindowState win, int transit) {
@@ -2261,21 +2213,20 @@
// Display task switcher for ALT-TAB or Meta-TAB.
if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
- if (mRecentAppsDialogHeldModifiers == 0 && !keyguardOn) {
+ if (mRecentAppsHeldModifiers == 0 && !keyguardOn) {
final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)
|| KeyEvent.metaStateHasModifiers(
shiftlessModifiers, KeyEvent.META_META_ON)) {
- mRecentAppsDialogHeldModifiers = shiftlessModifiers;
- showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW);
+ mRecentAppsHeldModifiers = shiftlessModifiers;
+ showRecentApps(true);
return -1;
}
}
- } else if (!down && mRecentAppsDialogHeldModifiers != 0
- && (metaState & mRecentAppsDialogHeldModifiers) == 0) {
- mRecentAppsDialogHeldModifiers = 0;
- showOrHideRecentAppsDialog(keyguardOn ? RECENT_APPS_BEHAVIOR_DISMISS :
- RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH);
+ } else if (!down && mRecentAppsHeldModifiers != 0
+ && (metaState & mRecentAppsHeldModifiers) == 0) {
+ mRecentAppsHeldModifiers = 0;
+ hideRecentApps();
}
// Handle keyboard language switching.
@@ -2390,7 +2341,7 @@
Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
- // TODO: This only stops the factory-installed search manager.
+ // TODO: This only stops the factory-installed search manager.
// Need to formalize an API to handle others
SearchManager searchManager = getSearchManager();
if (searchManager != null) {
@@ -2448,7 +2399,7 @@
statusbar.cancelPreloadRecentApps();
}
} catch (RemoteException e) {
- Slog.e(TAG, "RemoteException when showing recent apps", e);
+ Slog.e(TAG, "RemoteException when cancelling recent apps preload", e);
// re-acquire status bar service next time it is needed.
mStatusBarService = null;
}
@@ -2457,19 +2408,46 @@
private void toggleRecentApps() {
mPreloadedRecentApps = false; // preloading no longer needs to be canceled
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
try {
IStatusBarService statusbar = getStatusBarService();
if (statusbar != null) {
statusbar.toggleRecentApps();
}
} catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when toggling recent apps", e);
+ // re-acquire status bar service next time it is needed.
+ mStatusBarService = null;
+ }
+ }
+
+ private void showRecentApps(boolean triggeredFromAltTab) {
+ mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+ try {
+ IStatusBarService statusbar = getStatusBarService();
+ if (statusbar != null) {
+ statusbar.showRecentApps(triggeredFromAltTab);
+ }
+ } catch (RemoteException e) {
Slog.e(TAG, "RemoteException when showing recent apps", e);
// re-acquire status bar service next time it is needed.
mStatusBarService = null;
}
}
+ private void hideRecentApps() {
+ mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+ try {
+ IStatusBarService statusbar = getStatusBarService();
+ if (statusbar != null) {
+ statusbar.hideRecentApps();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when closing recent apps", e);
+ // re-acquire status bar service next time it is needed.
+ mStatusBarService = null;
+ }
+ }
+
/**
* A home key -> launch home action was detected. Take the appropriate action
* given the situation with the keyguard.
@@ -3058,7 +3036,7 @@
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ "): IN_SCREEN, INSET_DECOR");
// This is the case for a normal activity window: we want it
// to cover all of the screen space, and it can take care of
@@ -3342,7 +3320,7 @@
if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
+ ": sim=#" + Integer.toHexString(sim)
- + " attach=" + attached + " type=" + attrs.type
+ + " attach=" + attached + " type=" + attrs.type
+ String.format(" flags=0x%08x", fl)
+ " pf=" + pf.toShortString() + " df=" + df.toShortString()
+ " of=" + of.toShortString()
@@ -3391,7 +3369,7 @@
mForceStatusBarFromKeyguard = false;
mForcingShowNavBar = false;
mForcingShowNavBarLayer = -1;
-
+
mHideLockScreen = false;
mAllowLockscreenWhenOn = false;
mDismissKeyguard = DISMISS_KEYGUARD_NONE;
@@ -4235,12 +4213,16 @@
void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
if (ActivityManagerNative.isSystemReady()) {
- IAudioService audioService = getAudioService();
- if (audioService != null) {
- try {
- audioService.dispatchMediaKeyEventUnderWakelock(event);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
+ if (USE_SESSIONS) {
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
+ } else {
+ IAudioService audioService = getAudioService();
+ if (audioService != null) {
+ try {
+ audioService.dispatchMediaKeyEventUnderWakelock(event);
+ } catch (RemoteException e) {
+ Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
+ }
}
}
}
@@ -4466,7 +4448,7 @@
}
public void dismissKeyguardLw() {
- if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
mHandler.post(new Runnable() {
public void run() {
if (mKeyguardDelegate.isDismissable()) {
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
index 2f0d7d6..bc55ed1 100644
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -123,7 +123,7 @@
}
@Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_TAB) {
// Ignore all meta keys other than SHIFT. The app switch key could be a
// fallback action chorded with ALT, META or even CTRL depending on the key map.
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index e26747c..be20616 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -36,12 +36,14 @@
import android.media.AudioService;
import android.os.AsyncTask;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -49,6 +51,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.Xml;
@@ -56,6 +59,7 @@
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.google.android.util.AbstractMessageParser.MusicTrack;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -91,6 +95,10 @@
final SparseArray<HashMap<String, Ops>> mUidOps
= new SparseArray<HashMap<String, Ops>>();
+ private int mDeviceOwnerUid;
+ private final SparseIntArray mProfileOwnerUids = new SparseIntArray();
+ private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
+
public final static class Ops extends SparseArray<Op> {
public final String packageName;
public final int uid;
@@ -548,6 +556,9 @@
verifyIncomingUid(uid);
verifyIncomingOp(code);
synchronized (this) {
+ if (isOpRestricted(uid, code)) {
+ return AppOpsManager.MODE_IGNORED;
+ }
Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
@@ -631,6 +642,9 @@
return AppOpsManager.MODE_ERRORED;
}
Op op = getOpLocked(ops, code, true);
+ if (isOpRestricted(uid, code)) {
+ return AppOpsManager.MODE_IGNORED;
+ }
if (op.duration == -1) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
@@ -665,6 +679,9 @@
return AppOpsManager.MODE_ERRORED;
}
Op op = getOpLocked(ops, code, true);
+ if (isOpRestricted(uid, code)) {
+ return AppOpsManager.MODE_IGNORED;
+ }
final int switchCode = AppOpsManager.opToSwitch(code);
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
@@ -830,6 +847,23 @@
return op;
}
+ private boolean isOpRestricted(int uid, int code) {
+ int userHandle = UserHandle.getUserId(uid);
+ boolean[] opRestrictions = mOpRestrictions.get(userHandle);
+ if ((opRestrictions != null) && opRestrictions[code]) {
+ if (userHandle == UserHandle.USER_OWNER) {
+ if (uid != mDeviceOwnerUid) {
+ return true;
+ }
+ } else {
+ if (uid != mProfileOwnerUids.get(userHandle, -1)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
void readState() {
synchronized (mFile) {
synchronized (this) {
@@ -1167,4 +1201,66 @@
int mode;
ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
}
+
+ @Override
+ public void setDeviceOwner(String packageName) throws RemoteException {
+ checkSystemUid("setDeviceOwner");
+ try {
+ mDeviceOwnerUid = mContext.getPackageManager().getPackageUid(packageName,
+ UserHandle.USER_OWNER);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not find Device Owner UID");
+ mDeviceOwnerUid = -1;
+ throw new IllegalArgumentException("Could not find device owner package "
+ + packageName);
+ }
+ }
+
+ @Override
+ public void setProfileOwner(String packageName, int userHandle) throws RemoteException {
+ checkSystemUid("setProfileOwner");
+ try {
+ int uid = mContext.getPackageManager().getPackageUid(packageName,
+ userHandle);
+ mProfileOwnerUids.put(userHandle, uid);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not find Profile Owner UID");
+ mProfileOwnerUids.put(userHandle, -1);
+ throw new IllegalArgumentException("Could not find profile owner package "
+ + packageName);
+ }
+ }
+
+ @Override
+ public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
+ checkSystemUid("setUserRestrictions");
+ boolean[] opRestrictions = mOpRestrictions.get(userHandle);
+ if (opRestrictions == null) {
+ opRestrictions = new boolean[AppOpsManager._NUM_OP];
+ mOpRestrictions.put(userHandle, opRestrictions);
+ }
+ for (int i = 0; i < opRestrictions.length; ++i) {
+ String restriction = AppOpsManager.opToRestriction(i);
+ if (restriction != null) {
+ opRestrictions[i] = restrictions.getBoolean(restriction, false);
+ } else {
+ opRestrictions[i] = false;
+ }
+ }
+ }
+
+ @Override
+ public void removeUser(int userHandle) throws RemoteException {
+ checkSystemUid("removeUser");
+ mOpRestrictions.remove(userHandle);
+ mProfileOwnerUids.removeAt(mProfileOwnerUids.indexOfKey(userHandle));
+ }
+
+ private void checkSystemUid(String function) {
+ int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID) {
+ throw new SecurityException(function + " must by called by the system");
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 982dce0..cc132be 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,7 +20,7 @@
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
-import static android.net.ConnectivityManager.NetworkCallbacks;
+import static android.net.ConnectivityManager.NetworkCallbackListener;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_DUMMY;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
@@ -193,6 +193,9 @@
private static final boolean DBG = true;
private static final boolean VDBG = true; // STOPSHIP
+ // network sampling debugging
+ private static final boolean SAMPLE_DBG = false;
+
private static final boolean LOGD_RULES = false;
// TODO: create better separation between radio types and network types
@@ -219,10 +222,10 @@
// Set network sampling interval at 12 minutes, this way, even if the timers get
// aggregated, it will fire at around 15 minutes, which should allow us to
// aggregate this timer with other timers (specially the socket keep alive timers)
- private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60);
+ private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 12 * 60);
// start network sampling a minute after booting ...
- private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60);
+ private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 60);
AlarmManager mAlarmManager;
@@ -504,10 +507,14 @@
TelephonyManager mTelephonyManager;
+ // sequence number for Networks
private final static int MIN_NET_ID = 10; // some reserved marks
private final static int MAX_NET_ID = 65535;
private int mNextNetId = MIN_NET_ID;
+ // sequence number of NetworkRequests
+ private int mNextNetworkRequestId = 1;
+
public ConnectivityService(Context context, INetworkManagementService netd,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
// Currently, omitting a NetworkFactory will create one internally
@@ -523,7 +530,7 @@
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
- mDefaultRequest = new NetworkRequest(netCap, true);
+ mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId());
NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
NetworkRequestInfo.REQUEST);
mNetworkRequests.put(mDefaultRequest, nri);
@@ -770,6 +777,10 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
+ private synchronized int nextNetworkRequestId() {
+ return mNextNetworkRequestId++;
+ }
+
private synchronized int nextNetId() {
int netId = mNextNetId;
if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
@@ -3216,6 +3227,7 @@
// tell the network currently servicing this that it's no longer interested
NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
if (affectedNetwork != null) {
+ mNetworkForRequestId.remove(nri.request.requestId);
affectedNetwork.networkRequests.remove(nri.request.requestId);
if (VDBG) {
log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
@@ -5267,7 +5279,7 @@
throw new IllegalArgumentException("Bad timeout specified");
}
NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
- networkCapabilities));
+ networkCapabilities), false, nextNetworkRequestId());
if (DBG) log("requestNetwork for " + networkRequest);
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
NetworkRequestInfo.REQUEST);
@@ -5293,7 +5305,7 @@
enforceAccessPermission();
NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
- networkCapabilities));
+ networkCapabilities), false, nextNetworkRequestId());
if (DBG) log("listenForNetwork for " + networkRequest);
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
NetworkRequestInfo.LISTEN);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 0b9570d..50553ee 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -2369,20 +2369,20 @@
void setEnabledSessionInMainThread(SessionState session) {
if (mEnabledSession != session) {
- if (mEnabledSession != null) {
+ if (mEnabledSession != null && mEnabledSession.session != null) {
try {
if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
- mEnabledSession.method.setSessionEnabled(
- mEnabledSession.session, false);
+ mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
} catch (RemoteException e) {
}
}
mEnabledSession = session;
- try {
- if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
- session.method.setSessionEnabled(
- session.session, true);
- } catch (RemoteException e) {
+ if (mEnabledSession != null && mEnabledSession.session != null) {
+ try {
+ if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
+ mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
+ } catch (RemoteException e) {
+ }
}
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e54e5d0..11fc941 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1847,10 +1847,10 @@
return true;
}
if (mGeocodeProvider != null) {
- if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
+ if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
}
for (LocationProviderProxy proxy : mProxyProviders) {
- if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
+ if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
}
return false;
}
@@ -1876,19 +1876,23 @@
"or UID of a currently bound location provider");
}
- private boolean doesPackageHaveUid(int uid, String packageName) {
+ /**
+ * Returns true if the given package belongs to the given uid.
+ */
+ private boolean doesUidHavePackage(int uid, String packageName) {
if (packageName == null) {
return false;
}
- try {
- ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
- if (appInfo.uid != uid) {
- return false;
- }
- } catch (NameNotFoundException e) {
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ if (packageNames == null) {
return false;
}
- return true;
+ for (String name : packageNames) {
+ if (packageName.equals(name)) {
+ return true;
+ }
+ }
+ return false;
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bab5b9c..7abc75f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7087,50 +7087,7 @@
rti.description = tr.lastDescription;
rti.stackId = tr.stack.mStackId;
rti.userId = tr.userId;
-
- // Traverse upwards looking for any break between main task activities and
- // utility activities.
- final ArrayList<ActivityRecord> activities = tr.mActivities;
- int activityNdx;
- final int numActivities = activities.size();
- for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
- ++activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.intent != null &&
- (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
- != 0) {
- break;
- }
- }
- if (activityNdx > 0) {
- // Traverse downwards starting below break looking for set label, icon.
- // Note that if there are activities in the task but none of them set the
- // recent activity values, then we do not fall back to the last set
- // values in the TaskRecord.
- rti.activityValues = new ActivityManager.RecentsActivityValues();
- for (--activityNdx; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.activityValues != null) {
- if (rti.activityValues.label == null) {
- rti.activityValues.label = r.activityValues.label;
- tr.lastActivityValues.label = r.activityValues.label;
- }
- if (rti.activityValues.icon == null) {
- rti.activityValues.icon = r.activityValues.icon;
- tr.lastActivityValues.icon = r.activityValues.icon;
- }
- if (rti.activityValues.colorPrimary == 0) {
- rti.activityValues.colorPrimary = r.activityValues.colorPrimary;
- tr.lastActivityValues.colorPrimary = r.activityValues.colorPrimary;
- }
- }
- }
- } else {
- // If there are no activity records in this task, then we use the last
- // resolved values
- rti.activityValues =
- new ActivityManager.RecentsActivityValues(tr.lastActivityValues);
- }
+ rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
return rti;
}
@@ -7261,11 +7218,12 @@
}
@Override
- public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues rav) {
+ public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) {
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.activityValues = rav;
+ r.taskDescription = td;
+ r.task.updateTaskDescription();
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9582ac7..dbe2ca1 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -149,7 +149,7 @@
boolean mStartingWindowShown = false;
ActivityContainer mInitialActivityContainer;
- ActivityManager.RecentsActivityValues activityValues; // the recents information for this activity
+ ActivityManager.TaskDescription taskDescription; // the recents information for this activity
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c1e5e5b..33e59a7 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -742,19 +742,10 @@
int w = mThumbnailWidth;
int h = mThumbnailHeight;
if (w < 0) {
- Configuration config = res.getConfiguration();
- boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
- if (useAlternateRecents) {
- mThumbnailWidth = w =
- res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
- mThumbnailHeight = h =
- res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
- } else {
- mThumbnailWidth = w =
- res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
- mThumbnailHeight = h =
- res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
- }
+ mThumbnailWidth = w =
+ res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
+ mThumbnailHeight = h =
+ res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
}
if (w > 0) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5d744e6..ef9c711 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1816,7 +1816,7 @@
}
targetStack = sourceTask.stack;
targetStack.moveToFront();
- mWindowManager.moveTaskToTop(sourceTask.taskId);
+ mWindowManager.moveTaskToTop(targetStack.topTask().taskId);
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
// In this case, we are adding the activity to an existing
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 908bfbd..249422b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -623,8 +623,8 @@
pw.println(" --charged: only output data since last charged.");
pw.println(" --reset: reset the stats, clearing all current data.");
pw.println(" --write: force write current collected stats to disk.");
- pw.println(" --enable: enable an option: full-wake-history.");
- pw.println(" --disable: disable an option: full-wake-history.");
+ pw.println(" --enable: enable an option: full-wake-history, no-auto-reset.");
+ pw.println(" --disable: disable an option: full-wake-history, no-auto-reset.");
pw.println(" -h: print this help text.");
pw.println(" <package.name>: optional name of package to filter output by.");
}
@@ -640,6 +640,10 @@
synchronized (mStats) {
mStats.setRecordAllWakeLocksLocked(enable);
}
+ } else if ("no-auto-reset".equals(args[i])) {
+ synchronized (mStats) {
+ mStats.setNoAutoReset(enable);
+ }
} else {
pw.println("Unknown enable/disable option: " + args[i]);
dumpHelp(pw);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index be884e7..6d66b29 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -58,8 +58,8 @@
// This represents the last resolved activity values for this task
// NOTE: This value needs to be persisted with each task
- ActivityManager.RecentsActivityValues lastActivityValues =
- new ActivityManager.RecentsActivityValues();
+ ActivityManager.TaskDescription lastTaskDescription =
+ new ActivityManager.TaskDescription();
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
@@ -486,6 +486,48 @@
return null;
}
+ /** Updates the last task description values. */
+ void updateTaskDescription() {
+ // Traverse upwards looking for any break between main task activities and
+ // utility activities.
+ int activityNdx;
+ final int numActivities = mActivities.size();
+ for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+ ++activityNdx) {
+ final ActivityRecord r = mActivities.get(activityNdx);
+ if (r.intent != null &&
+ (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+ != 0) {
+ break;
+ }
+ }
+ if (activityNdx > 0) {
+ // Traverse downwards starting below break looking for set label, icon.
+ // Note that if there are activities in the task but none of them set the
+ // recent activity values, then we do not fall back to the last set
+ // values in the TaskRecord.
+ String label = null;
+ Bitmap icon = null;
+ int colorPrimary = 0;
+ for (--activityNdx; activityNdx >= 0; --activityNdx) {
+ final ActivityRecord r = mActivities.get(activityNdx);
+ if (r.taskDescription != null) {
+ if (label == null) {
+ label = r.taskDescription.getLabel();
+ }
+ if (icon == null) {
+ icon = r.taskDescription.getIcon();
+ }
+ if (colorPrimary == 0) {
+ colorPrimary = r.taskDescription.getPrimaryColor();
+
+ }
+ }
+ }
+ lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 3884ab0..096ab66 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -74,6 +74,14 @@
mIsStarted = false;
mIsRunning = false;
mLP = new LinkProperties();
+
+ // If this is a runtime restart, it's possible that clatd is already
+ // running, but we don't know about it. If so, stop it.
+ try {
+ if (mNMService.isClatdStarted()) {
+ mNMService.stopClatd();
+ }
+ } catch(RemoteException e) {} // Well, we tried.
}
/**
@@ -198,13 +206,13 @@
NetworkUtils.resetConnections(
CLAT_INTERFACE_NAME,
NetworkUtils.RESET_IPV4_ADDRESSES);
+ mBaseLP.removeStackedLink(mLP);
+ updateConnectivityService();
}
Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
" removed, mIsRunning = " + mIsRunning + " -> false");
mIsRunning = false;
- mBaseLP.removeStackedLink(mLP);
mLP.clear();
- updateConnectivityService();
Slog.i(TAG, "mLP = " + mLP);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5327ef4..986cb9b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -24,6 +24,7 @@
import android.os.Message;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import libcore.util.EmptyArray;
@@ -79,11 +80,12 @@
new SparseArray<HdmiCecDeviceInfo>();
// Set-like container for all local devices' logical address.
// Key and value are same.
- private final SparseArray<Integer> mLocalLogicalAddresses =
- new SparseArray<Integer>();
+ private final SparseIntArray mLocalAddresses = new SparseIntArray();
// Private constructor. Use HdmiCecController.create().
private HdmiCecController() {
+ // TODO: Consider restoring the local device addresses from persistent storage
+ // to allocate the same addresses again if possible.
}
/**
@@ -109,6 +111,44 @@
}
/**
+ * Initialize {@link #mLocalAddresses} by allocating logical addresses for each hosted type.
+ *
+ * @param deviceTypes local device types
+ */
+ void initializeLocalDevices(int[] deviceTypes) {
+ for (int deviceType : deviceTypes) {
+ int preferred = getPreferredAddress(deviceType);
+ allocateLogicalAddress(deviceType, preferred, new AllocateLogicalAddressCallback() {
+ @Override
+ public void onAllocated(int deviceType, int logicalAddress) {
+ addLogicalAddress(logicalAddress);
+ }
+ });
+ }
+ }
+
+ /**
+ * Get the preferred address for a given type.
+ *
+ * @param deviceType logical device type to get the address for
+ * @return preferred address; {@link HdmiCec#ADDR_UNREGISTERED} if not available.
+ */
+ private int getPreferredAddress(int deviceType) {
+ // Uses the data restored from persistent memory at boot up if they are available.
+ // Otherwise we return UNREGISTERED indicating there is no preferred address.
+ // Note that for address SPECIFIC_USE(14), HdmiCec.getTypeFromAddress() returns DEVICE_TV,
+ // meaning that we do not support device type video processor yet.
+ for (int i = 0; i < mLocalAddresses.size(); ++i) {
+ int address = mLocalAddresses.keyAt(i);
+ int type = HdmiCec.getTypeFromAddress(address);
+ if (type == deviceType) {
+ return address;
+ }
+ }
+ return HdmiCec.ADDR_UNREGISTERED;
+ }
+
+ /**
* Interface to report allocated logical address.
*/
interface AllocateLogicalAddressCallback {
@@ -322,7 +362,7 @@
*/
int addLogicalAddress(int newLogicalAddress) {
if (HdmiCec.isValidAddress(newLogicalAddress)) {
- mLocalLogicalAddresses.append(newLogicalAddress, newLogicalAddress);
+ mLocalAddresses.put(newLogicalAddress, newLogicalAddress);
return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
} else {
return -1;
@@ -337,7 +377,7 @@
void clearLogicalAddress() {
// TODO: consider to backup logical address so that new logical address
// allocation can use it as preferred address.
- mLocalLogicalAddresses.clear();
+ mLocalAddresses.clear();
nativeClearLogicalAddress(mNativePtr);
}
@@ -382,7 +422,7 @@
// Can access command targeting devices available in local device or
// broadcast command.
return address == HdmiCec.ADDR_BROADCAST
- || mLocalLogicalAddresses.get(address) != null;
+ || mLocalAddresses.indexOfKey(address) < 0;
}
private void onReceiveCommand(HdmiCecMessage message) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index ed48c12..7c136db 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -54,7 +54,10 @@
@Override
public void onStart() {
mCecController = HdmiCecController.create(this);
- if (mCecController == null) {
+ if (mCecController != null) {
+ mCecController.initializeLocalDevices(getContext().getResources()
+ .getIntArray(com.android.internal.R.array.config_hdmiCecLogicalDeviceType));
+ } else {
Slog.i(TAG, "Device does not support HDMI-CEC.");
}
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
index 1c5cacd..b31153b 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
@@ -26,7 +26,7 @@
import android.media.routeprovider.RouteRequest;
import android.media.session.RouteEvent;
import android.media.session.RouteInfo;
-import android.media.session.Session;
+import android.media.session.MediaSession;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9677577..00d364b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -24,16 +24,16 @@
import android.media.session.ISessionControllerCallback;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
-import android.media.session.SessionController;
-import android.media.session.MediaMetadata;
+import android.media.session.MediaController;
import android.media.session.RouteCommand;
import android.media.session.RouteInfo;
import android.media.session.RouteOptions;
import android.media.session.RouteEvent;
-import android.media.session.Session;
-import android.media.session.SessionInfo;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionInfo;
import android.media.session.RouteInterface;
import android.media.session.PlaybackState;
+import android.media.MediaMetadata;
import android.media.Rating;
import android.os.Bundle;
import android.os.Handler;
@@ -85,7 +85,7 @@
private final int mOwnerPid;
private final int mOwnerUid;
private final int mUserId;
- private final SessionInfo mSessionInfo;
+ private final MediaSessionInfo mSessionInfo;
private final String mTag;
private final ControllerStub mController;
private final SessionStub mSession;
@@ -120,7 +120,7 @@
mOwnerPid = ownerPid;
mOwnerUid = ownerUid;
mUserId = userId;
- mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), ownerPackageName);
+ mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName);
mTag = tag;
mController = new ControllerStub();
mSession = new SessionStub();
@@ -130,7 +130,7 @@
}
/**
- * Get the binder for the {@link Session}.
+ * Get the binder for the {@link MediaSession}.
*
* @return The session binder apps talk to.
*/
@@ -139,7 +139,7 @@
}
/**
- * Get the binder for the {@link SessionController}.
+ * Get the binder for the {@link MediaController}.
*
* @return The controller binder apps talk to.
*/
@@ -170,7 +170,7 @@
*
* @return Info that identifies this session.
*/
- public SessionInfo getSessionInfo() {
+ public MediaSessionInfo getSessionInfo() {
return mSessionInfo;
}
@@ -209,7 +209,7 @@
* @return True if this is a system priority session, false otherwise
*/
public boolean isSystemPriority() {
- return (mFlags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
+ return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
}
/**
@@ -221,7 +221,7 @@
public void selectRoute(RouteInfo route) {
synchronized (mLock) {
if (route != mRoute) {
- disconnect(Session.DISCONNECT_REASON_ROUTE_CHANGED);
+ disconnect(MediaSession.DISCONNECT_REASON_ROUTE_CHANGED);
}
mRoute = route;
}
@@ -335,7 +335,7 @@
}
public boolean isTransportControlEnabled() {
- return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ return hasFlag(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
}
@Override
@@ -353,7 +353,7 @@
return;
}
if (isConnected()) {
- disconnectLocked(Session.DISCONNECT_REASON_SESSION_DESTROYED);
+ disconnectLocked(MediaSession.DISCONNECT_REASON_SESSION_DESTROYED);
}
mRoute = null;
mRequest = null;
@@ -365,6 +365,10 @@
return mSessionCb.mCb;
}
+ public void sendMediaButton(KeyEvent ke, ResultReceiver cb) {
+ mSessionCb.sendMediaButton(ke, cb);
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mTag + " " + this);
@@ -536,7 +540,7 @@
@Override
public void disconnect() {
- MediaSessionRecord.this.disconnect(Session.DISCONNECT_REASON_PROVIDER_DISCONNECTED);
+ MediaSessionRecord.this.disconnect(MediaSession.DISCONNECT_REASON_PROVIDER_DISCONNECTED);
}
};
@@ -565,7 +569,7 @@
@Override
public void setFlags(int flags) {
- if ((flags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+ if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
int pid = getCallingPid();
int uid = getCallingUid();
mService.enforcePhoneStatePermission(pid, uid);
@@ -623,7 +627,7 @@
public void disconnectFromRoute(RouteInfo route) {
if (route != null && mRoute != null
&& TextUtils.equals(route.getId(), mRoute.getId())) {
- disconnect(Session.DISCONNECT_REASON_SESSION_DISCONNECTED);
+ disconnect(MediaSession.DISCONNECT_REASON_SESSION_DISCONNECTED);
}
}
@@ -645,11 +649,11 @@
mCb = cb;
}
- public void sendMediaButton(KeyEvent keyEvent) {
+ public void sendMediaButton(KeyEvent keyEvent, ResultReceiver cb) {
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
try {
- mCb.onMediaButton(mediaButtonIntent);
+ mCb.onMediaButton(mediaButtonIntent, cb);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
}
@@ -785,7 +789,7 @@
@Override
public void sendMediaButton(KeyEvent mediaButtonIntent) {
- mSessionCb.sendMediaButton(mediaButtonIntent);
+ mSessionCb.sendMediaButton(mediaButtonIntent, null);
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 78f3b5f..d9e45f5ba 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -17,9 +17,12 @@
package com.android.server.media;
import android.Manifest;
+import android.app.Activity;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.routeprovider.RouteRequest;
import android.media.session.ISession;
@@ -27,16 +30,20 @@
import android.media.session.ISessionManager;
import android.media.session.RouteInfo;
import android.media.session.RouteOptions;
-import android.media.session.Session;
+import android.media.session.MediaSession;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
+import android.view.KeyEvent;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -64,6 +71,7 @@
// = new ArrayList<MediaRouteProviderProxy>();
private final Object mLock = new Object();
private final Handler mHandler = new Handler();
+ private final PowerManager.WakeLock mMediaEventWakeLock;
private MediaSessionRecord mPrioritySession;
private int mCurrentUserId = -1;
@@ -79,6 +87,8 @@
super(context);
mSessionManagerImpl = new SessionManagerImpl();
mPriorityStack = new MediaSessionStack();
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
}
@Override
@@ -377,7 +387,7 @@
/*
* When a session is created the following things need to happen.
- * 1. It's callback binder needs a link to death
+ * 1. Its callback binder needs a link to death
* 2. It needs to be added to all sessions.
* 3. It needs to be added to the priority stack.
* 4. It needs to be added to the relevant user record.
@@ -493,7 +503,7 @@
MediaSessionRecord session = mSessions.get(i);
MediaSessionService.this.destroySessionLocked(session);
if (session.isConnected()) {
- session.disconnect(Session.DISCONNECT_REASON_USER_STOPPING);
+ session.disconnect(MediaSession.DISCONNECT_REASON_USER_STOPPING);
}
}
}
@@ -585,9 +595,10 @@
}
class SessionManagerImpl extends ISessionManager.Stub {
- // TODO add createSessionAsUser, pass user-id to
- // ActivityManagerNative.handleIncomingUser and stash result for use
- // when starting services on that session's behalf.
+ private static final String EXTRA_WAKELOCK_ACQUIRED =
+ "android.media.AudioService.WAKELOCK_ACQUIRED";
+ private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
+
@Override
public ISession createSession(String packageName, ISessionCallback cb, String tag,
int userId) throws RemoteException {
@@ -644,6 +655,59 @@
}
}
+ /**
+ * Handles the dispatching of the media button events to one of the
+ * registered listeners, or if there was none, broadcast an
+ * ACTION_MEDIA_BUTTON intent to the rest of the system.
+ *
+ * @param keyEvent a non-null KeyEvent whose key code is one of the
+ * supported media buttons
+ * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
+ * while this key event is dispatched.
+ */
+ @Override
+ public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ if (keyEvent == null || !KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
+ Log.w(TAG, "Attempted to dispatch null or non-media key event.");
+ return;
+ }
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ if (needWakeLock) {
+ mMediaEventWakeLock.acquire();
+ }
+ synchronized (mLock) {
+ MediaSessionRecord mbSession = mPriorityStack
+ .getDefaultMediaButtonSession(mCurrentUserId);
+ if (mbSession != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Sending media key to " + mbSession.getSessionInfo());
+ }
+ mbSession.sendMediaButton(keyEvent,
+ needWakeLock ? mKeyEventDoneReceiver : null);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Sending media key ordered broadcast");
+ }
+ // Fallback to legacy behavior
+ Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ if (needWakeLock) {
+ keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED,
+ WAKELOCK_RELEASE_ON_FINISHED);
+ }
+ getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+ null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
@@ -678,6 +742,36 @@
}
}
}
+
+ ResultReceiver mKeyEventDoneReceiver = new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ synchronized (mLock) {
+ if (mMediaEventWakeLock.isHeld()) {
+ mMediaEventWakeLock.release();
+ }
+ }
+ }
+ };
+
+ BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return;
+ }
+ synchronized (mLock) {
+ if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
+ && mMediaEventWakeLock.isHeld()) {
+ mMediaEventWakeLock.release();
+ }
+ }
+ }
+ };
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index f89b14a..7ba9212 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -17,7 +17,7 @@
package com.android.server.media;
import android.media.session.PlaybackState;
-import android.media.session.Session;
+import android.media.session.MediaSession;
import android.os.UserHandle;
import java.io.PrintWriter;
@@ -62,7 +62,7 @@
*/
public void addSession(MediaSessionRecord record) {
mSessions.add(record);
- if ((record.getFlags() & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+ if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
mGlobalPrioritySession = record;
}
clearCache();
@@ -134,7 +134,7 @@
public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) {
if (mCachedTransportControlList == null) {
mCachedTransportControlList = getPriorityListLocked(true,
- Session.FLAG_HANDLES_TRANSPORT_CONTROLS, userId);
+ MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS, userId);
}
return mCachedTransportControlList;
}
@@ -170,7 +170,7 @@
return mCachedButtonReceiver;
}
ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
- Session.FLAG_HANDLES_MEDIA_BUTTONS, userId);
+ MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userId);
if (records.size() > 0) {
mCachedButtonReceiver = records.get(0);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f9eabcd..61b3a89 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1663,7 +1663,10 @@
updateAllSharedLibrariesLPw();
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
- adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
+ // NOTE: We ignore potential failures here during a system scan (like
+ // the rest of the commands above) because there's precious little we
+ // can do about it. A settings error is reported, though.
+ adjustCpuAbisForSharedUserLPw(setting.packages, null,
false /* force dexopt */, false /* defer dexopt */);
}
@@ -5613,8 +5616,12 @@
if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
- adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
- true, forceDex, (scanMode & SCAN_DEFER_DEX) != 0);
+ if (!adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
+ pkg.applicationInfo.cpuAbi,
+ forceDex, (scanMode & SCAN_DEFER_DEX) != 0)) {
+ mLastScanError = PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
+ return null;
+ }
}
// We don't expect installation to fail beyond this point,
if ((scanMode&SCAN_MONITOR) != 0) {
@@ -5960,9 +5967,8 @@
return pkg;
}
- public void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
- boolean doDexOpt, boolean forceDexOpt, boolean deferDexOpt) {
- String requiredInstructionSet = null;
+ private boolean adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
+ String requiredInstructionSet, boolean forceDexOpt, boolean deferDexOpt) {
PackageSetting requirer = null;
for (PackageSetting ps : packagesForUser) {
if (ps.cpuAbiString != null) {
@@ -5970,20 +5976,16 @@
if (requiredInstructionSet != null) {
if (!instructionSet.equals(requiredInstructionSet)) {
// We have a mismatch between instruction sets (say arm vs arm64).
- //
- // TODO: We should rescan all the packages in a shared UID to check if
- // they do contain shared libs for other ABIs in addition to the ones we've
- // already extracted. For example, the package might contain both arm64-v8a
- // and armeabi-v7a shared libs, and we'd have chosen arm64-v8a on 64 bit
- // devices.
- String errorMessage = "Instruction set mismatch, " + requirer.pkg.packageName
- + " requires " + requiredInstructionSet + " whereas " + ps.pkg.packageName
+ // bail out.
+ String errorMessage = "Instruction set mismatch, "
+ + ((requirer == null) ? "[caller]" : requirer.pkg)
+ + " requires " + requiredInstructionSet + " whereas " + ps.pkg
+ " requires " + instructionSet;
Slog.e(TAG, errorMessage);
reportSettingsProblem(Log.WARN, errorMessage);
// Give up, don't bother making any other changes to the package settings.
- return;
+ return false;
}
} else {
requiredInstructionSet = instructionSet;
@@ -5999,14 +6001,20 @@
if (ps.pkg != null) {
ps.pkg.applicationInfo.cpuAbi = requirer.cpuAbiString;
Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + ps.cpuAbiString);
- if (doDexOpt) {
- performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true);
+
+ if (performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true) == DEX_OPT_FAILED) {
+ ps.cpuAbiString = null;
+ ps.pkg.applicationInfo.cpuAbi = null;
+ return false;
+ } else {
mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
}
}
}
}
}
+
+ return true;
}
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 60212bf..131d05b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -40,6 +40,7 @@
import android.os.IUserManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AtomicFile;
@@ -50,6 +51,7 @@
import android.util.TimeUtils;
import android.util.Xml;
+import com.android.internal.app.IAppOpsService;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -162,6 +164,8 @@
private int mNextSerialNumber;
private int mUserVersion = 0;
+ private IAppOpsService mAppOpsService;
+
private static UserManagerService sInstance;
public static UserManagerService getInstance() {
@@ -236,6 +240,15 @@
void systemReady() {
mUserPackageMonitor.register(mContext, null, UserHandle.ALL, false);
userForeground(UserHandle.USER_OWNER);
+ mAppOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
+ for (int i = 0; i < mUserIds.length; ++i) {
+ try {
+ mAppOpsService.setUserRestrictions(mUserRestrictions.get(mUserIds[i]), mUserIds[i]);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+ }
+ }
}
@Override
@@ -482,6 +495,14 @@
synchronized (mPackagesLock) {
mUserRestrictions.get(userId).clear();
mUserRestrictions.get(userId).putAll(restrictions);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppOpsService.setUserRestrictions(mUserRestrictions.get(userId), userId);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
writeUserLocked(mUsers.get(userId));
}
}
@@ -1116,6 +1137,11 @@
return false;
}
mRemovingUserIds.put(userHandle, true);
+ try {
+ mAppOpsService.removeUser(userHandle);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
+ }
// Set this to a partially created user, so that the user will be purged
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
@@ -1125,6 +1151,14 @@
user.flags |= UserInfo.FLAG_DISABLED;
writeUserLocked(user);
}
+
+ if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+ && user.isManagedProfile()) {
+ // Send broadcast to notify system that the user removed was a
+ // managed user.
+ sendProfileRemovedBroadcast(user.profileGroupId, user.id);
+ }
+
if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
int res;
try {
@@ -1151,7 +1185,6 @@
// wiping the user's system directory and removing from the user list
long ident = Binder.clearCallingIdentity();
try {
- final boolean isManaged = getUserInfo(userHandle).isManagedProfile();
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
@@ -1172,11 +1205,6 @@
removeUserStateLocked(userHandle);
}
}
- // Send broadcast to notify system that the user removed was a
- // managed user.
- if (isManaged) {
- sendProfileRemovedBroadcast(userHandle);
- }
}
}.start();
}
@@ -1228,11 +1256,11 @@
parent.delete();
}
- private void sendProfileRemovedBroadcast(int userHandle) {
+ private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {
Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(userHandle));
- // Note: This makes an assumption that the parent owner is user 0.
- mContext.sendBroadcastAsUser(managedProfileIntent, UserHandle.OWNER, null);
+ managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
+ mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null);
}
@Override
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 738ad32..2c38d3c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -460,6 +460,24 @@
}
@Override
+ public void showRecentApps(boolean triggeredFromAltTab) {
+ if (mBar != null) {
+ try {
+ mBar.showRecentApps(triggeredFromAltTab);
+ } catch (RemoteException ex) {}
+ }
+ }
+
+ @Override
+ public void hideRecentApps() {
+ if (mBar != null) {
+ try {
+ mBar.hideRecentApps();
+ } catch (RemoteException ex) {}
+ }
+ }
+
+ @Override
public void setCurrentUser(int newUserId) {
if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId);
mCurrentUserId = newUserId;
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
index a87bf95..db2d4ee 100644
--- a/services/core/java/com/android/server/task/StateChangedListener.java
+++ b/services/core/java/com/android/server/task/StateChangedListener.java
@@ -19,9 +19,9 @@
import com.android.server.task.controllers.TaskStatus;
/**
- * Interface through which a {@link StateController} informs the
- * {@link com.android.server.task.TaskManagerService} that there are some tasks potentially ready
- * to be run.
+ * Interface through which a {@link com.android.server.task.controllers.StateController} informs
+ * the {@link com.android.server.task.TaskManagerService} that there are some tasks potentially
+ * ready to be run.
*/
public interface StateChangedListener {
/**
diff --git a/services/core/java/com/android/server/task/TaskCompletedListener.java b/services/core/java/com/android/server/task/TaskCompletedListener.java
new file mode 100644
index 0000000..0210442
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskCompletedListener.java
@@ -0,0 +1,38 @@
+/*
+ * 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.server.task;
+
+/**
+ * Used for communication between {@link com.android.server.task.TaskServiceContext} and the
+ * {@link com.android.server.task.TaskManagerService}.
+ */
+public interface TaskCompletedListener {
+
+ /**
+ * Callback for when a task is completed.
+ * @param needsReschedule Whether the implementing class should reschedule this task.
+ */
+ public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule);
+
+ /**
+ * Callback for when the implementing class needs to clean up the
+ * {@link com.android.server.task.TaskServiceContext}. The scheduler can get this callback
+ * several times if the TaskServiceContext got into a bad state (for e.g. the client crashed
+ * and it needs to clean up).
+ */
+ public void onAllTasksCompleted(int serviceToken);
+}
diff --git a/services/core/java/com/android/server/task/TaskList.java b/services/core/java/com/android/server/task/TaskList.java
deleted file mode 100644
index d2b8440..0000000
--- a/services/core/java/com/android/server/task/TaskList.java
+++ /dev/null
@@ -1,78 +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.server.task;
-
-import android.content.ComponentName;
-import android.content.Task;
-
-import com.android.server.task.controllers.TaskStatus;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Maintain a list of classes, and accessor methods/logic for these tasks.
- * This class offers the following functionality:
- * - When a task is added, it will determine if the task requirements have changed (update) and
- * whether the controllers need to be updated.
- * - Persists Tasks, figures out when to to rewrite the Task to disk.
- * - Is threadsafe.
- * - Handles rescheduling of tasks.
- * - When a periodic task is executed and must be re-added.
- * - When a task fails and the client requests that it be retried with backoff.
- */
-public class TaskList {
-
- final List<TaskStatus> mTasks;
-
- TaskList() {
- mTasks = intialiseTaskMapFromDisk();
- }
-
- /**
- * Add a task to the master list, persisting it if necessary.
- * @param task Task to add.
- * @param persistable true if the TaskQueue should persist this task to the disk.
- * @return true if this operation was successful. If false, this task was neither added nor
- * persisted.
- */
- // TODO: implement this when i decide whether i want to key by TaskStatus
- public boolean add(Task task, boolean persistable) {
- return true;
- }
-
- /**
- * Remove the provided task. Will also delete the task if it was persisted. Note that this
- * function does not return the validity of the operation, as we assume a delete will always
- * succeed.
- * @param task Task to remove.
- */
- public void remove(Task task) {
-
- }
-
- /**
- *
- * @return
- */
- // TODO: Implement this.
- private List<TaskStatus> intialiseTaskMapFromDisk() {
- return new ArrayList<TaskStatus>();
- }
-}
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
index 5df4b2a..6d208ff 100644
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -17,16 +17,15 @@
package com.android.server.task;
import android.content.Context;
+import android.content.Task;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.util.Log;
import android.util.SparseArray;
import com.android.server.task.controllers.TaskStatus;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Responsible for taking tasks representing work to be performed by a client app, and determining
* based on the criteria specified when that task should be run against the client application's
@@ -34,25 +33,29 @@
* @hide
*/
public class TaskManagerService extends com.android.server.SystemService
- implements StateChangedListener {
+ implements StateChangedListener, TaskCompletedListener {
+ static final String TAG = "TaskManager";
/** Master list of tasks. */
- private final TaskList mTaskList;
+ private final TaskStore mTasks;
+
+ /** Check the pending queue and start any tasks. */
+ static final int MSG_RUN_PENDING = 0;
+ /** Initiate the stop task flow. */
+ static final int MSG_STOP_TASK = 1;
+ /** */
+ static final int MSG_CHECK_TASKS = 2;
/**
* Track Services that have currently active or pending tasks. The index is provided by
* {@link TaskStatus#getServiceToken()}
*/
- private final SparseArray<TaskServiceContext> mPendingTaskServices =
+ private final SparseArray<TaskServiceContext> mActiveServices =
new SparseArray<TaskServiceContext>();
private final TaskHandler mHandler;
private class TaskHandler extends Handler {
- /** Check the pending queue and start any tasks. */
- static final int MSG_RUN_PENDING = 0;
- /** Initiate the stop task flow. */
- static final int MSG_STOP_TASK = 1;
public TaskHandler(Looper looper) {
super(looper);
@@ -67,21 +70,42 @@
case MSG_STOP_TASK:
break;
+ case MSG_CHECK_TASKS:
+ checkTasks();
+ break;
}
}
/**
- * Helper to post a message to this handler that will run through the pending queue and
- * start any tasks it can.
+ * Called when we need to run through the list of all tasks and start/stop executing one or
+ * more of them.
*/
- void sendRunPendingTasksMessage() {
- Message m = Message.obtain(this, MSG_RUN_PENDING);
- m.sendToTarget();
+ private void checkTasks() {
+ synchronized (mTasks) {
+ final SparseArray<TaskStatus> tasks = mTasks.getTasks();
+ for (int i = 0; i < tasks.size(); i++) {
+ TaskStatus ts = tasks.valueAt(i);
+ if (ts.isReady() && ! isCurrentlyActive(ts)) {
+ assignTaskToServiceContext(ts);
+ }
+ }
+ }
}
+ }
- void sendOnStopMessage(TaskStatus taskStatus) {
-
- }
+ /**
+ * Entry point from client to schedule the provided task.
+ * This will add the task to the
+ * @param task Task object containing execution parameters
+ * @param userId The id of the user this task is for.
+ * @param uId The package identifier of the application this task is for.
+ * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
+ * of this task.
+ * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+ */
+ public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
+ TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
+ return 0;
}
/**
@@ -95,7 +119,7 @@
*/
public TaskManagerService(Context context) {
super(context);
- mTaskList = new TaskList();
+ mTasks = new TaskStore(context);
mHandler = new TaskHandler(context.getMainLooper());
}
@@ -104,20 +128,18 @@
}
+ // StateChangedListener implementations.
+
/**
- * Offboard work to our handler thread as quickly as possible, b/c this call is probably being
+ * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
* made on the main thread.
- * @param taskStatus The state of the task which has changed.
+ * For now this takes the task and if it's ready to run it will run it. In future we might not
+ * provide the task, so that the StateChangedListener has to run through its list of tasks to
+ * see which are ready. This will further decouple the controllers from the execution logic.
*/
@Override
public void onTaskStateChanged(TaskStatus taskStatus) {
- if (taskStatus.isReady()) {
-
- } else {
- if (mPendingTaskServices.get(taskStatus.getServiceToken()) != null) {
- // The task is either pending or being executed, which we have to cancel.
- }
- }
+ postCheckTasksMessage();
}
@@ -125,4 +147,60 @@
public void onTaskDeadlineExpired(TaskStatus taskStatus) {
}
+
+ // TaskCompletedListener implementations.
+
+ /**
+ * A task just finished executing. We fetch the
+ * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
+ * whether we want to reschedule we readd it to the controllers.
+ * @param serviceToken key for the service context in {@link #mActiveServices}.
+ * @param taskId Id of the task that is complete.
+ * @param needsReschedule Whether the implementing class should reschedule this task.
+ */
+ @Override
+ public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) {
+ final TaskServiceContext serviceContext = mActiveServices.get(serviceToken);
+ if (serviceContext == null) {
+ Log.e(TAG, "Task completed for invalid service context; " + serviceToken);
+ return;
+ }
+
+ }
+
+ @Override
+ public void onAllTasksCompleted(int serviceToken) {
+
+ }
+
+ private void assignTaskToServiceContext(TaskStatus ts) {
+ TaskServiceContext serviceContext =
+ mActiveServices.get(ts.getServiceToken());
+ if (serviceContext == null) {
+ serviceContext = new TaskServiceContext(this, mHandler.getLooper(), ts);
+ mActiveServices.put(ts.getServiceToken(), serviceContext);
+ }
+ serviceContext.addPendingTask(ts);
+ }
+
+ /**
+ * @param ts TaskStatus we are querying against.
+ * @return Whether or not the task represented by the status object is currently being run or
+ * is pending.
+ */
+ private boolean isCurrentlyActive(TaskStatus ts) {
+ TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken());
+ if (serviceContext == null) {
+ return false;
+ }
+ return serviceContext.hasTaskPending(ts);
+ }
+
+ /**
+ * Post a message to {@link #mHandler} to run through the list of tasks and start/stop any that
+ * are eligible.
+ */
+ private void postCheckTasksMessage() {
+ mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
index 65c6fa5..b51cbb3 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -16,79 +16,500 @@
package com.android.server.task;
+import android.app.ActivityManager;
import android.app.task.ITaskCallback;
import android.app.task.ITaskService;
+import android.app.task.TaskParams;
import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.Task;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
import com.android.server.task.controllers.TaskStatus;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* Maintains information required to bind to a {@link android.app.task.TaskService}. This binding
- * can then be reused to start concurrent tasks on the TaskService. Information here is unique
- * within this service.
+ * is reused to start concurrent tasks on the TaskService. Information here is unique
+ * to the service.
* Functionality provided by this class:
* - Managages wakelock for the service.
* - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
* -
*/
public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+ private static final String TAG = "TaskServiceContext";
+ /** Define the maximum # of tasks allowed to run on a service at once. */
+ private static final int defaultMaxActiveTasksPerService =
+ ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
+ /** Amount of time a task is allowed to execute for before being considered timed-out. */
+ private static final long EXECUTING_TIMESLICE_MILLIS = 5 * 60 * 1000;
+ /** Amount of time the TaskManager will wait for a response from an app for a message. */
+ private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
+ /** String prefix for all wakelock names. */
+ private static final String TM_WAKELOCK_PREFIX = "*task*/";
+ private static final String[] VERB_STRINGS = {
+ "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_PENDING"
+ };
+
+ // States that a task occupies while interacting with the client.
+ private static final int VERB_STARTING = 0;
+ private static final int VERB_EXECUTING = 1;
+ private static final int VERB_STOPPING = 2;
+ private static final int VERB_PENDING = 3;
+
+ // Messages that result from interactions with the client service.
+ /** System timed out waiting for a response. */
+ private static final int MSG_TIMEOUT = 0;
+ /** Received a callback from client. */
+ private static final int MSG_CALLBACK = 1;
+ /** Run through list and start any ready tasks.*/
+ private static final int MSG_CHECK_PENDING = 2;
+ /** Cancel an active task. */
+ private static final int MSG_CANCEL = 3;
+ /** Add a pending task. */
+ private static final int MSG_ADD_PENDING = 4;
+ /** Client crashed, so we need to wind things down. */
+ private static final int MSG_SHUTDOWN = 5;
+
+ /** Used to identify this task service context when communicating with the TaskManager. */
+ final int token;
final ComponentName component;
- int uid;
+ final int userId;
ITaskService service;
+ private final Handler mCallbackHandler;
+ /** Tasks that haven't been sent to the client for execution yet. */
+ private final SparseArray<ActiveTask> mPending;
+ /** Used for service binding, etc. */
+ private final Context mContext;
+ /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
+ final private TaskCompletedListener mCompletedListener;
+ private final PowerManager.WakeLock mWakeLock;
/** Whether this service is actively bound. */
boolean mBound;
- TaskServiceContext(Task task) {
- this.component = task.getService();
- }
-
- public void stopTask() {
-
- }
-
- public void startTask(Task task) {
-
+ TaskServiceContext(TaskManagerService taskManager, Looper looper, TaskStatus taskStatus) {
+ mContext = taskManager.getContext();
+ this.component = taskStatus.getServiceComponent();
+ this.token = taskStatus.getServiceToken();
+ this.userId = taskStatus.getUserId();
+ mCallbackHandler = new TaskServiceHandler(looper);
+ mPending = new SparseArray<ActiveTask>();
+ mCompletedListener = taskManager;
+ final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ TM_WAKELOCK_PREFIX + component.getPackageName());
+ mWakeLock.setWorkSource(new WorkSource(taskStatus.getUid()));
+ mWakeLock.setReferenceCounted(false);
}
@Override
public void taskFinished(int taskId, boolean reschedule) {
-
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+ .sendToTarget();
}
@Override
- public void acknowledgeStopMessage(int taskId) {
-
+ public void acknowledgeStopMessage(int taskId, boolean reschedule) {
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+ .sendToTarget();
}
@Override
- public void acknowledgeStartMessage(int taskId) {
+ public void acknowledgeStartMessage(int taskId, boolean ongoing) {
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, ongoing ? 1 : 0).sendToTarget();
+ }
+ /**
+ * Queue up this task to run on the client. This will execute the task as quickly as possible.
+ * @param ts Status of the task to run.
+ */
+ public void addPendingTask(TaskStatus ts) {
+ final TaskParams params = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
+ final ActiveTask newTask = new ActiveTask(params, VERB_PENDING);
+ mCallbackHandler.obtainMessage(MSG_ADD_PENDING, newTask).sendToTarget();
+ if (!mBound) {
+ Intent intent = new Intent().setComponent(component);
+ boolean binding = mContext.bindServiceAsUser(intent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+ new UserHandle(userId));
+ if (!binding) {
+ Log.e(TAG, component.getShortClassName() + " unavailable.");
+ cancelPendingTask(ts);
+ }
+ }
+ }
+
+ /**
+ * Called externally when a task that was scheduled for execution should be cancelled.
+ * @param ts The status of the task to cancel.
+ */
+ public void cancelPendingTask(TaskStatus ts) {
+ mCallbackHandler.obtainMessage(MSG_CANCEL, ts.getTaskId(), -1 /* arg2 */)
+ .sendToTarget();
+ }
+
+ /**
+ * MSG_TIMEOUT is sent with the {@link com.android.server.task.TaskServiceContext.ActiveTask}
+ * set in the {@link Message#obj} field. This makes it easier to remove timeouts for a given
+ * ActiveTask.
+ * @param op Operation that is taking place.
+ */
+ private void scheduleOpTimeOut(ActiveTask op) {
+ mCallbackHandler.removeMessages(MSG_TIMEOUT, op);
+
+ final long timeoutMillis = (op.verb == VERB_EXECUTING) ?
+ EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
+ if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+ Slog.d(TAG, "Scheduling time out for '" + component.getShortClassName() + "' tId: " +
+ op.params.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
+ }
+ Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, op);
+ mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
}
/**
* @return true if this task is pending or active within this context.
*/
public boolean hasTaskPending(TaskStatus taskStatus) {
- return true;
+ synchronized (mPending) {
+ return mPending.get(taskStatus.getTaskId()) != null;
+ }
}
public boolean isBound() {
return mBound;
}
+ /**
+ * We acquire/release the wakelock on onServiceConnected/unbindService. This mirrors the work
+ * we intend to send to the client - we stop sending work when the service is unbound so until
+ * then we keep the wakelock.
+ * @param name The concrete component name of the service that has
+ * been connected.
+ * @param service The IBinder of the Service's communication channel,
+ */
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
-
mBound = true;
+ this.service = ITaskService.Stub.asInterface(service);
+ // Remove all timeouts. We've just connected to the client so there are no other
+ // MSG_TIMEOUTs at this point.
+ mCallbackHandler.removeMessages(MSG_TIMEOUT);
+ mWakeLock.acquire();
+ mCallbackHandler.obtainMessage(MSG_CHECK_PENDING).sendToTarget();
}
+ /**
+ * When the client service crashes we can have a couple tasks executing, in various stages of
+ * undress. We'll cancel all of them and request that they be rescheduled.
+ * @param name The concrete component name of the service whose
+ */
@Override
public void onServiceDisconnected(ComponentName name) {
- mBound = false;
+ // Service disconnected... probably client crashed.
+ startShutdown();
+ }
+
+ /**
+ * We don't just shutdown outright - we make sure the scheduler isn't going to send us any more
+ * tasks, then we do the shutdown.
+ */
+ private void startShutdown() {
+ mCompletedListener.onAllTasksCompleted(token);
+ mCallbackHandler.obtainMessage(MSG_SHUTDOWN).sendToTarget();
+ }
+
+ /** Tracks a task across its various state changes. */
+ private static class ActiveTask {
+ final TaskParams params;
+ int verb;
+ AtomicBoolean cancelled = new AtomicBoolean();
+
+ ActiveTask(TaskParams params, int verb) {
+ this.params = params;
+ this.verb = verb;
+ }
+
+ @Override
+ public String toString() {
+ return params.getTaskId() + " " + VERB_STRINGS[verb];
+ }
+ }
+
+ /**
+ * Handles the lifecycle of the TaskService binding/callbacks, etc. The convention within this
+ * class is to append 'H' to each function name that can only be called on this handler. This
+ * isn't strictly necessary because all of these functions are private, but helps clarity.
+ */
+ private class TaskServiceHandler extends Handler {
+ TaskServiceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_ADD_PENDING:
+ if (message.obj != null) {
+ ActiveTask pendingTask = (ActiveTask) message.obj;
+ mPending.put(pendingTask.params.getTaskId(), pendingTask);
+ }
+ // fall through.
+ case MSG_CHECK_PENDING:
+ checkPendingTasksH();
+ break;
+ case MSG_CALLBACK:
+ ActiveTask receivedCallback = mPending.get(message.arg1);
+ removeMessages(MSG_TIMEOUT, receivedCallback);
+
+ if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+ Log.d(TAG, "MSG_CALLBACK of : " + receivedCallback);
+ }
+
+ if (receivedCallback.verb == VERB_STARTING) {
+ final boolean workOngoing = message.arg2 == 1;
+ handleStartedH(receivedCallback, workOngoing);
+ } else if (receivedCallback.verb == VERB_EXECUTING ||
+ receivedCallback.verb == VERB_STOPPING) {
+ final boolean reschedule = message.arg2 == 1;
+ handleFinishedH(receivedCallback, reschedule);
+ } else {
+ if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unrecognised callback: " + receivedCallback);
+ }
+ }
+ break;
+ case MSG_CANCEL:
+ ActiveTask cancelled = mPending.get(message.arg1);
+ handleCancelH(cancelled);
+ break;
+ case MSG_TIMEOUT:
+ // Timeout msgs have the ActiveTask ref so we can remove them easily.
+ handleOpTimeoutH((ActiveTask) message.obj);
+ break;
+ case MSG_SHUTDOWN:
+ handleShutdownH();
+ break;
+ default:
+ Log.e(TAG, "Unrecognised message: " + message);
+ }
+ }
+
+ /**
+ * State behaviours.
+ * VERB_STARTING -> Successful start, change task to VERB_EXECUTING and post timeout.
+ * _PENDING -> Error
+ * _EXECUTING -> Error
+ * _STOPPING -> Error
+ */
+ private void handleStartedH(ActiveTask started, boolean workOngoing) {
+ switch (started.verb) {
+ case VERB_STARTING:
+ started.verb = VERB_EXECUTING;
+ if (!workOngoing) {
+ // Task is finished already so fast-forward to handleFinished.
+ handleFinishedH(started, false);
+ return;
+ } else if (started.cancelled.get()) {
+ // Cancelled *while* waiting for acknowledgeStartMessage from client.
+ handleCancelH(started);
+ return;
+ } else {
+ scheduleOpTimeOut(started);
+ }
+ break;
+ default:
+ Log.e(TAG, "Handling started task but task wasn't starting! " + started);
+ return;
+ }
+ }
+
+ /**
+ * VERB_EXECUTING -> Client called taskFinished(), clean up and notify done.
+ * _STOPPING -> Successful finish, clean up and notify done.
+ * _STARTING -> Error
+ * _PENDING -> Error
+ */
+ private void handleFinishedH(ActiveTask executedTask, boolean reschedule) {
+ switch (executedTask.verb) {
+ case VERB_EXECUTING:
+ case VERB_STOPPING:
+ closeAndCleanupTaskH(executedTask, reschedule);
+ break;
+ default:
+ Log.e(TAG, "Got an execution complete message for a task that wasn't being" +
+ "executed. " + executedTask);
+ }
+ }
+
+ /**
+ * A task can be in various states when a cancel request comes in:
+ * VERB_PENDING -> Remove from queue.
+ * _STARTING -> Mark as cancelled and wait for {@link #acknowledgeStartMessage(int)}.
+ * _EXECUTING -> call {@link #sendStopMessageH}}.
+ * _ENDING -> No point in doing anything here, so we ignore.
+ */
+ private void handleCancelH(ActiveTask cancelledTask) {
+ switch (cancelledTask.verb) {
+ case VERB_PENDING:
+ mPending.remove(cancelledTask.params.getTaskId());
+ break;
+ case VERB_STARTING:
+ cancelledTask.cancelled.set(true);
+ break;
+ case VERB_EXECUTING:
+ cancelledTask.verb = VERB_STOPPING;
+ sendStopMessageH(cancelledTask);
+ break;
+ case VERB_STOPPING:
+ // Nada.
+ break;
+ default:
+ Log.e(TAG, "Cancelling a task without a valid verb: " + cancelledTask);
+ break;
+ }
+ }
+
+ /**
+ * This TaskServiceContext is shutting down. Remove all the tasks from the pending queue
+ * and reschedule them as if they had failed.
+ * Before posting this message, caller must invoke
+ * {@link com.android.server.task.TaskCompletedListener#onAllTasksCompleted(int)}.
+ */
+ private void handleShutdownH() {
+ for (int i = 0; i < mPending.size(); i++) {
+ ActiveTask at = mPending.valueAt(i);
+ closeAndCleanupTaskH(at, true /* needsReschedule */);
+ }
+ mWakeLock.release();
+ mContext.unbindService(TaskServiceContext.this);
+ service = null;
+ mBound = false;
+ }
+
+ /**
+ * MSG_TIMEOUT gets processed here.
+ * @param timedOutTask The task that timed out.
+ */
+ private void handleOpTimeoutH(ActiveTask timedOutTask) {
+ if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+ Log.d(TAG, "MSG_TIMEOUT of " + component.getShortClassName() + " : "
+ + timedOutTask.params.getTaskId());
+ }
+
+ final int taskId = timedOutTask.params.getTaskId();
+ switch (timedOutTask.verb) {
+ case VERB_STARTING:
+ // Client unresponsive - wedged or failed to respond in time. We don't really
+ // know what happened so let's log it and notify the TaskManager
+ // FINISHED/NO-RETRY.
+ Log.e(TAG, "No response from client for onStartTask '" +
+ component.getShortClassName() + "' tId: " + taskId);
+ closeAndCleanupTaskH(timedOutTask, false /* needsReschedule */);
+ break;
+ case VERB_STOPPING:
+ // At least we got somewhere, so fail but ask the TaskManager to reschedule.
+ Log.e(TAG, "No response from client for onStopTask, '" +
+ component.getShortClassName() + "' tId: " + taskId);
+ closeAndCleanupTaskH(timedOutTask, true /* needsReschedule */);
+ break;
+ case VERB_EXECUTING:
+ // Not an error - client ran out of time.
+ Log.i(TAG, "Client timed out while executing (no taskFinished received)." +
+ " Reporting failure and asking for reschedule. " +
+ component.getShortClassName() + "' tId: " + taskId);
+ sendStopMessageH(timedOutTask);
+ break;
+ default:
+ Log.e(TAG, "Handling timeout for an unknown active task state: "
+ + timedOutTask);
+ return;
+ }
+ }
+
+ /**
+ * Called on the handler thread. Checks the state of the pending queue and starts the task
+ * if it can. The task only starts if there is capacity on the service.
+ */
+ private void checkPendingTasksH() {
+ if (!mBound) {
+ return;
+ }
+ for (int i = 0; i < mPending.size() && i < defaultMaxActiveTasksPerService; i++) {
+ ActiveTask at = mPending.valueAt(i);
+ if (at.verb != VERB_PENDING) {
+ continue;
+ }
+ sendStartMessageH(at);
+ }
+ }
+
+ /**
+ * Already running, need to stop. Rund on handler.
+ * @param stoppingTask Task we are sending onStopMessage for. This task will be moved from
+ * VERB_EXECUTING -> VERB_STOPPING.
+ */
+ private void sendStopMessageH(ActiveTask stoppingTask) {
+ mCallbackHandler.removeMessages(MSG_TIMEOUT, stoppingTask);
+ if (stoppingTask.verb != VERB_EXECUTING) {
+ Log.e(TAG, "Sending onStopTask for a task that isn't started. " + stoppingTask);
+ // TODO: Handle error?
+ return;
+ }
+ try {
+ service.stopTask(stoppingTask.params);
+ stoppingTask.verb = VERB_STOPPING;
+ scheduleOpTimeOut(stoppingTask);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending onStopTask to client.", e);
+ closeAndCleanupTaskH(stoppingTask, false);
+ }
+ }
+
+ /** Start the task on the service. */
+ private void sendStartMessageH(ActiveTask pendingTask) {
+ if (pendingTask.verb != VERB_PENDING) {
+ Log.e(TAG, "Sending onStartTask for a task that isn't pending. " + pendingTask);
+ // TODO: Handle error?
+ }
+ try {
+ service.startTask(pendingTask.params);
+ pendingTask.verb = VERB_STARTING;
+ scheduleOpTimeOut(pendingTask);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending onStart message to '" + component.getShortClassName()
+ + "' ", e);
+ }
+ }
+
+ /**
+ * The provided task has finished, either by calling
+ * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+ * or from acknowledging the stop message we sent. Either way, we're done tracking it and
+ * we want to clean up internally.
+ */
+ private void closeAndCleanupTaskH(ActiveTask completedTask, boolean reschedule) {
+ removeMessages(MSG_TIMEOUT, completedTask);
+ mPending.remove(completedTask.params.getTaskId());
+ if (mPending.size() == 0) {
+ startShutdown();
+ }
+ mCompletedListener.onTaskCompleted(token, completedTask.params.getTaskId(), reschedule);
+ }
}
}
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
new file mode 100644
index 0000000..3bfc8a5
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskStore.java
@@ -0,0 +1,103 @@
+/*
+ * 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.server.task;
+
+import android.content.Context;
+import android.content.Task;
+import android.util.SparseArray;
+
+import com.android.server.task.controllers.TaskStatus;
+
+/**
+ * Maintain a list of classes, and accessor methods/logic for these tasks.
+ * This class offers the following functionality:
+ * - When a task is added, it will determine if the task requirements have changed (update) and
+ * whether the controllers need to be updated.
+ * - Persists Tasks, figures out when to to rewrite the Task to disk.
+ * - Is threadsafe.
+ * - Handles rescheduling of tasks.
+ * - When a periodic task is executed and must be re-added.
+ * - When a task fails and the client requests that it be retried with backoff.
+ * - This class is <strong>not</strong> thread-safe.
+ */
+public class TaskStore {
+
+ /**
+ * Master list, indexed by {@link com.android.server.task.controllers.TaskStatus#hashCode()}.
+ */
+ final SparseArray<TaskStatus> mTasks;
+ final Context mContext;
+
+ TaskStore(Context context) {
+ mTasks = intialiseTaskMapFromDisk();
+ mContext = context;
+ }
+
+ /**
+ * Add a task to the master list, persisting it if necessary.
+ * Will first check to see if the task already exists. If so, it will replace it.
+ * {@link android.content.pm.PackageManager} is queried to see if the calling package has
+ * permission to
+ * @param task Task to add.
+ * @return The initialised TaskStatus object if this operation was successful, null if it
+ * failed.
+ */
+ public TaskStatus addNewTaskForUser(Task task, int userId, int uId,
+ boolean canPersistTask) {
+ TaskStatus taskStatus = TaskStatus.getForTaskAndUser(task, userId, uId);
+ if (canPersistTask && task.isPeriodic()) {
+ if (writeStatusToDisk()) {
+ mTasks.put(taskStatus.hashCode(), taskStatus);
+ }
+ }
+ return taskStatus;
+ }
+
+ /**
+ * Remove the provided task. Will also delete the task if it was persisted. Note that this
+ * function does not return the validity of the operation, as we assume a delete will always
+ * succeed.
+ * @param task Task to remove.
+ */
+ public void remove(Task task) {
+
+ }
+
+ /**
+ * Every time the state changes we write all the tasks in one swathe, instead of trying to
+ * track incremental changes.
+ */
+ private boolean writeStatusToDisk() {
+ return true;
+ }
+
+ /**
+ *
+ * @return
+ */
+ // TODO: Implement this.
+ private SparseArray<TaskStatus> intialiseTaskMapFromDisk() {
+ return new SparseArray<TaskStatus>();
+ }
+
+ /**
+ * @return The live array of TaskStatus objects.
+ */
+ public SparseArray<TaskStatus> getTasks() {
+ return mTasks;
+ }
+}
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
index 5cca77c..6a4e1f3 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -41,6 +41,11 @@
private final BroadcastReceiver mConnectivityChangedReceiver =
new ConnectivityChangedReceiver();
+ /** Track whether the latest active network is metered. */
+ private boolean mMetered;
+ /** Track whether the latest active network is connected. */
+ private boolean mConnectivity;
+
public ConnectivityController(TaskManagerService service) {
super(service);
// Register connectivity changed BR.
@@ -53,6 +58,8 @@
@Override
public void maybeTrackTaskState(TaskStatus taskStatus) {
if (taskStatus.hasConnectivityConstraint() || taskStatus.hasMeteredConstraint()) {
+ taskStatus.connectivityConstraintSatisfied.set(mConnectivity);
+ taskStatus.meteredConstraintSatisfied.set(mMetered);
mTrackedTasks.add(taskStatus);
}
}
@@ -63,19 +70,16 @@
}
/**
- * @param isConnected Whether the active network is connected for the given uid
- * @param isMetered Whether the active network is metered for the given uid. This is
- * necessarily false if <code>isConnected</code> is false.
* @param userId Id of the user for whom we are updating the connectivity state.
*/
- private void updateTrackedTasks(boolean isConnected, boolean isMetered, int userId) {
+ private void updateTrackedTasks(int userId) {
for (TaskStatus ts : mTrackedTasks) {
if (ts.userId != userId) {
continue;
}
- boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(isConnected);
- boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(isMetered);
- if (prevIsConnected != isConnected || prevIsMetered != isMetered) {
+ boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
+ boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
+ if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
mStateChangedListener.onTaskStateChanged(ts);
}
}
@@ -83,12 +87,13 @@
class ConnectivityChangedReceiver extends BroadcastReceiver {
/**
- * We'll receive connectivity changes for each user here, which we'll process independently.
+ * We'll receive connectivity changes for each user here, which we process independently.
* We are only interested in the active network here. We're only interested in the active
* network, b/c the end result of this will be for apps to try to hit the network.
* @param context The Context in which the receiver is running.
* @param intent The Intent being received.
*/
+ // TODO: Test whether this will be called twice for each user.
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
@@ -103,13 +108,13 @@
// This broadcast gets sent a lot, only update if the active network has changed.
if (activeNetwork.getType() == networkType) {
final int userid = context.getUserId();
- boolean isMetered = false;
- boolean isConnected =
+ mMetered = false;
+ mConnectivity =
!intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
- if (isConnected) { // No point making the call if we know there's no conn.
- isMetered = connManager.isActiveNetworkMetered();
+ if (mConnectivity) { // No point making the call if we know there's no conn.
+ mMetered = connManager.isActiveNetworkMetered();
}
- updateTrackedTasks(isConnected, isMetered, userid);
+ updateTrackedTasks(userid);
}
} else {
Log.w(TAG, "Unrecognised action in intent: " + action);
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/task/controllers/IdleController.java
new file mode 100644
index 0000000..a319a31
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/IdleController.java
@@ -0,0 +1,180 @@
+/*
+ * 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.server.task.controllers;
+
+import java.util.ArrayList;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.server.task.TaskManagerService;
+
+public class IdleController extends StateController {
+ private static final String TAG = "IdleController";
+ private static final boolean DEBUG = false;
+
+ // Policy: we decide that we're "idle" if the device has been unused /
+ // screen off or dreaming for at least this long
+ private static final long INACTIVITY_IDLE_THRESHOLD = 71 * 60 * 1000; // millis; 71 min
+ private static final long IDLE_WINDOW_SLOP = 5 * 60 * 1000; // 5 minute window, to be nice
+
+ private static final String ACTION_TRIGGER_IDLE =
+ "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
+
+ final ArrayList<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+ IdlenessTracker mIdleTracker;
+
+ // Singleton factory
+ private static Object sCreationLock = new Object();
+ private static volatile IdleController sController;
+
+ public IdleController getController(TaskManagerService service) {
+ synchronized (sCreationLock) {
+ if (sController == null) {
+ sController = new IdleController(service);
+ }
+ return sController;
+ }
+ }
+
+ private IdleController(TaskManagerService service) {
+ super(service);
+ initIdleStateTracking();
+ }
+
+ /**
+ * StateController interface
+ */
+ @Override
+ public void maybeTrackTaskState(TaskStatus taskStatus) {
+ if (taskStatus.hasIdleConstraint()) {
+ synchronized (mTrackedTasks) {
+ mTrackedTasks.add(taskStatus);
+ taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
+ }
+ }
+ }
+
+ @Override
+ public void removeTaskStateIfTracked(TaskStatus taskStatus) {
+ synchronized (mTrackedTasks) {
+ mTrackedTasks.remove(taskStatus);
+ }
+ }
+
+ /**
+ * Interaction with the task manager service
+ */
+ void reportNewIdleState(boolean isIdle) {
+ synchronized (mTrackedTasks) {
+ for (TaskStatus task : mTrackedTasks) {
+ task.idleConstraintSatisfied.set(isIdle);
+ mStateChangedListener.onTaskStateChanged(task);
+ }
+ }
+ }
+
+ /**
+ * Idle state tracking, and messaging with the task manager when
+ * significant state changes occur
+ */
+ private void initIdleStateTracking() {
+ mIdleTracker = new IdlenessTracker();
+ mIdleTracker.startTracking();
+ }
+
+ class IdlenessTracker extends BroadcastReceiver {
+ private AlarmManager mAlarm;
+ private PendingIntent mIdleTriggerIntent;
+ boolean mIdle;
+
+ public IdlenessTracker() {
+ mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+ Intent intent = new Intent(ACTION_TRIGGER_IDLE);
+ intent.setComponent(new ComponentName(mContext, this.getClass()));
+ mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+
+ // at boot we presume that the user has just "interacted" with the
+ // device in some meaningful way
+ mIdle = false;
+ }
+
+ public boolean isIdle() {
+ return mIdle;
+ }
+
+ public void startTracking() {
+ IntentFilter filter = new IntentFilter();
+
+ // Screen state
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+
+ // Dreaming state
+ filter.addAction(Intent.ACTION_DREAMING_STARTED);
+ filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+
+ mContext.registerReceiver(this, filter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+
+ if (action.equals(Intent.ACTION_SCREEN_ON)
+ || action.equals(Intent.ACTION_DREAMING_STOPPED)) {
+ // possible transition to not-idle
+ if (mIdle) {
+ if (DEBUG) {
+ Slog.v(TAG, "exiting idle : " + action);
+ }
+ mAlarm.cancel(mIdleTriggerIntent);
+ mIdle = false;
+ reportNewIdleState(mIdle);
+ }
+ } else if (action.equals(Intent.ACTION_SCREEN_OFF)
+ || action.equals(Intent.ACTION_DREAMING_STARTED)) {
+ // when the screen goes off or dreaming starts, we schedule the
+ // alarm that will tell us when we have decided the device is
+ // truly idle.
+ long when = SystemClock.elapsedRealtime() + INACTIVITY_IDLE_THRESHOLD;
+ if (DEBUG) {
+ Slog.v(TAG, "Scheduling idle : " + action + " when=" + when);
+ }
+ mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
+ } else if (action.equals(ACTION_TRIGGER_IDLE)) {
+ // idle time starts now
+ if (!mIdle) {
+ if (DEBUG) {
+ Slog.v(TAG, "Idle trigger fired @ " + SystemClock.elapsedRealtime());
+ }
+ mIdle = true;
+ reportNewIdleState(mIdle);
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
index 230b049..d96fedc 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -18,6 +18,8 @@
import android.content.ComponentName;
import android.content.Task;
+import android.content.pm.PackageParser;
+import android.os.Bundle;
import android.os.SystemClock;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -36,7 +38,9 @@
public class TaskStatus {
final int taskId;
final int userId;
- ComponentName component;
+ final int uId;
+ final ComponentName component;
+ final Bundle extras;
final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
final AtomicBoolean timeConstraintSatisfied = new AtomicBoolean();
@@ -60,15 +64,17 @@
/** Generate a TaskStatus object for a given task and uid. */
// TODO: reimplement this to reuse these objects instead of creating a new one each time?
- static TaskStatus getForTaskAndUid(Task task, int uId) {
- return new TaskStatus(task, uId);
+ public static TaskStatus getForTaskAndUser(Task task, int userId, int uId) {
+ return new TaskStatus(task, userId, uId);
}
/** Set up the state of a newly scheduled task. */
- TaskStatus(Task task, int userId) {
+ TaskStatus(Task task, int userId, int uId) {
this.taskId = task.getTaskId();
this.userId = userId;
this.component = task.getService();
+ this.extras = task.getExtras();
+ this.uId = uId;
hasChargingConstraint = task.isRequireCharging();
hasIdleConstraint = task.isRequireDeviceIdle();
@@ -94,6 +100,26 @@
hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
}
+ public int getTaskId() {
+ return taskId;
+ }
+
+ public ComponentName getServiceComponent() {
+ return component;
+ }
+
+ public int getUserId() {
+ return userId;
+ }
+
+ public int getUid() {
+ return uId;
+ }
+
+ public Bundle getExtras() {
+ return extras;
+ }
+
boolean hasConnectivityConstraint() {
return hasConnectivityConstraint;
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 99ec242..c20e38c 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -679,7 +679,7 @@
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
int appWidth, int appHeight, int orientation,
- Rect containingFrame, Rect contentInsets, Configuration configuration) {
+ Rect containingFrame, Rect contentInsets) {
Animation a;
if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -700,15 +700,9 @@
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
- boolean useAlternateThumbnailAnimation = (configuration.smallestScreenWidthDp < 600);
- if (useAlternateThumbnailAnimation) {
- a = createAlternateThumbnailEnterExitAnimationLocked(
- getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
- transit, containingFrame, contentInsets);
- } else {
- a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
- appWidth, appHeight, transit);
- }
+ a = createAlternateThumbnailEnterExitAnimationLocked(
+ getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
+ transit, containingFrame, contentInsets);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
String animName = mNextAppTransitionScaleUp ?
"ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b61ba5c..c6fffbf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3194,7 +3194,7 @@
}
Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
- mCurConfiguration.orientation, containingFrame, contentInsets, mCurConfiguration);
+ mCurConfiguration.orientation, containingFrame, contentInsets);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = null;
@@ -8677,7 +8677,7 @@
wtoken.deferClearAllDrawn = false;
}
- boolean useAlternateThumbnailAnimation = (mCurConfiguration.smallestScreenWidthDp < 600);
+ boolean useAlternateThumbnailAnimation = true;
AppWindowAnimator appAnimator =
topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3c9d53e..1e79dcb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -46,6 +46,7 @@
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
@@ -151,6 +152,10 @@
static final int READY_TO_SHOW = 3;
/** Set when the window has been shown in the screen the first time. */
static final int HAS_DRAWN = 4;
+
+ private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN =
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+
static String drawStateToString(int state) {
switch (state) {
case NO_SURFACE: return "NO_SURFACE";
@@ -1176,9 +1181,15 @@
// content insets as well.
int offsetTop = Math.max(w.mSystemDecorRect.top, w.mContentInsets.top);
mTmpClipRect.set(w.mSystemDecorRect);
- mTmpClipRect.offset(0, -offsetTop);
- mTmpClipRect.intersect(mClipRect);
- mTmpClipRect.offset(0, offsetTop);
+ // Don't apply the workaround to apps explicitly requesting fullscreen layout.
+ if ((w.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
+ == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) {
+ mTmpClipRect.intersect(mClipRect);
+ } else {
+ mTmpClipRect.offset(0, -offsetTop);
+ mTmpClipRect.intersect(mClipRect);
+ mTmpClipRect.offset(0, offsetTop);
+ }
clipRect = mTmpClipRect;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 1647425..674c6f4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -39,6 +39,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
+import java.util.Set;
/**
* Stores and restores state for the Device and Profile owners. By definition there can be
@@ -137,6 +138,10 @@
return profileOwner != null ? profileOwner.name : null;
}
+ Set<Integer> getProfileOwnerKeys() {
+ return mProfileOwners.keySet();
+ }
+
boolean hasDeviceOwner() {
return mDeviceOwner != null;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1980d1e..e2cd4e2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import com.android.internal.R;
+import com.android.internal.app.IAppOpsService;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -237,6 +238,8 @@
}
};
+ private IAppOpsService mAppOpsService;
+
static class ActiveAdmin {
private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
private static final String TAG_DISABLE_CAMERA = "disable-camera";
@@ -1209,6 +1212,24 @@
loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
loadDeviceOwner();
}
+ mAppOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
+ if (mDeviceOwner != null) {
+ if (mDeviceOwner.hasDeviceOwner()) {
+ try {
+ mAppOpsService.setDeviceOwner(mDeviceOwner.getDeviceOwnerPackageName());
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+ }
+ }
+ for (Integer i : mDeviceOwner.getProfileOwnerKeys()) {
+ try {
+ mAppOpsService.setProfileOwner(mDeviceOwner.getProfileOwnerPackageName(i), i);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+ }
+ }
+ }
}
private void handlePasswordExpirationNotification(int userHandle) {
@@ -2953,6 +2974,14 @@
"Trying to set device owner but device owner is already set.");
}
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppOpsService.setDeviceOwner(packageName);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
if (mDeviceOwner == null) {
// Device owner is not set and does not exist, set it.
mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
@@ -3029,6 +3058,14 @@
throw new IllegalStateException(
"Trying to set profile owner but user is already set-up.");
}
+ long token = Binder.clearCallingIdentity();
+ try {
+ mAppOpsService.setProfileOwner(packageName, userHandle);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
if (mDeviceOwner == null) {
// Device owner state does not exist, create it.
mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 22e2a6e..9b3f7ac 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -124,8 +124,8 @@
"com.android.server.usb.UsbService$Lifecycle";
private static final String WIFI_SERVICE_CLASS =
"com.android.server.wifi.WifiService";
- private static final String WIFI_HOTSPOT_SERVICE_CLASS =
- "com.android.server.wifi.hotspot.WifiHotspotService";
+ private static final String WIFI_PASSPOINT_SERVICE_CLASS =
+ "com.android.server.wifi.passpoint.WifiPasspointService";
private static final String WIFI_P2P_SERVICE_CLASS =
"com.android.server.wifi.p2p.WifiP2pService";
private static final String HDMI_CEC_SERVICE_CLASS =
@@ -639,9 +639,9 @@
}
try {
- mSystemServiceManager.startService(WIFI_HOTSPOT_SERVICE_CLASS);
+ mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS);
} catch (Throwable e) {
- reportWtf("starting Wi-Fi HotspotService", e);
+ reportWtf("starting Wi-Fi PasspointService", e);
}
try {
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
new file mode 100644
index 0000000..6b7463c
--- /dev/null
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -0,0 +1,412 @@
+/*
+ * 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.Bundle;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Represents a connection to a remote endpoint that carries voice traffic.
+ */
+public abstract class Connection {
+
+ private static String TAG = Connection.class.getSimpleName();
+
+ public interface Listener {
+ void onStateChanged(Connection c, int state);
+ void onAudioStateChanged(Connection c, CallAudioState state);
+ void onHandleChanged(Connection c, Uri newHandle);
+ void onSignalChanged(Connection c, Bundle details);
+ void onDisconnected(Connection c, int cause, String message);
+ void onDestroyed(Connection c);
+ }
+
+ public static class ListenerBase implements Listener {
+ /** {@inheritDoc} */
+ @Override
+ public void onStateChanged(Connection c, int state) {}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onAudioStateChanged(Connection c, CallAudioState state) {}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onHandleChanged(Connection c, Uri newHandle) {}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onSignalChanged(Connection c, Bundle details) {}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onDisconnected(Connection c, int cause, String message) {}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onDestroyed(Connection c) {}
+ }
+
+ public final class State {
+ private State() {}
+
+ public static final int NEW = 0;
+ public static final int RINGING = 1;
+ public static final int DIALING = 2;
+ public static final int ACTIVE = 3;
+ public static final int HOLDING = 4;
+ public static final int DISCONNECTED = 5;
+ }
+
+ private final Set<Listener> mListeners = new HashSet<>();
+ private int mState = State.NEW;
+ private CallAudioState mCallAudioState;
+ private Uri mHandle;
+
+ /**
+ * Create a new Connection.
+ */
+ protected Connection() {}
+
+ /**
+ * @return The handle (e.g., phone number) to which this Connection
+ * is currently communicating.
+ */
+ public final Uri getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * @return The state of this Connection.
+ *
+ * @hide
+ */
+ public final int getState() {
+ return mState;
+ }
+
+ /**
+ * @return The audio state of the call, describing how its audio is currently
+ * being routed by the system. This is {@code null} if this Connection
+ * does not directly know about its audio state.
+ */
+ public final CallAudioState getCallAudioState() {
+ return mCallAudioState;
+ }
+
+ /**
+ * Assign a listener to be notified of state changes.
+ *
+ * @param l A listener.
+ * @return This Connection.
+ *
+ * @hide
+ */
+ public final Connection addConnectionListener(Listener l) {
+ mListeners.add(l);
+ return this;
+ }
+
+ /**
+ * Remove a previously assigned listener that was being notified of state changes.
+ *
+ * @param l A Listener.
+ * @return This Connection.
+ *
+ * @hide
+ */
+ public final Connection removeConnectionListener(Listener l) {
+ mListeners.remove(l);
+ return this;
+ }
+
+ /**
+ * Play a DTMF tone in this Connection.
+ *
+ * @param c A DTMF character.
+ *
+ * @hide
+ */
+ public final void playDtmfTone(char c) {
+ Log.d(TAG, "playDtmfTone " + c);
+ onPlayDtmfTone(c);
+ }
+
+ /**
+ * Stop any DTMF tones which may be playing in this Connection.
+ *
+ * @hide
+ */
+ public final void stopDtmfTone() {
+ Log.d(TAG, "stopDtmfTone");
+ onStopDtmfTone();
+ }
+
+ /**
+ * Disconnect this Connection. If and when the Connection can comply with
+ * this request, it will transition to the {@link State#DISCONNECTED}
+ * state and notify its listeners.
+ *
+ * @hide
+ */
+ public final void disconnect() {
+ Log.d(TAG, "disconnect");
+ onDisconnect();
+ }
+
+ /**
+ * Abort this Connection. The Connection will immediately transition to
+ * the {@link State#DISCONNECTED} state, and send no notifications of this
+ * or any other future events.
+ *
+ * @hide
+ */
+ public final void abort() {
+ Log.d(TAG, "abort");
+ onAbort();
+ }
+
+ /**
+ * Place this Connection on hold. If and when the Connection can comply with
+ * this request, it will transition to the {@link State#HOLDING}
+ * state and notify its listeners.
+ *
+ * @hide
+ */
+ public final void hold() {
+ Log.d(TAG, "hold");
+ onHold();
+ }
+
+ /**
+ * Un-hold this Connection. If and when the Connection can comply with
+ * this request, it will transition to the {@link State#ACTIVE}
+ * state and notify its listeners.
+ *
+ * @hide
+ */
+ public final void unhold() {
+ Log.d(TAG, "unhold");
+ onUnhold();
+ }
+
+ /**
+ * Accept a {@link State#RINGING} Connection. If and when the Connection
+ * can comply with this request, it will transition to the {@link State#ACTIVE}
+ * state and notify its listeners.
+ *
+ * @hide
+ */
+ public final void answer() {
+ Log.d(TAG, "answer");
+ if (mState == State.RINGING) {
+ onAnswer();
+ }
+ }
+
+ /**
+ * Reject a {@link State#RINGING} Connection. If and when the Connection
+ * can comply with this request, it will transition to the {@link State#ACTIVE}
+ * state and notify its listeners.
+ *
+ * @hide
+ */
+ public final void reject() {
+ Log.d(TAG, "reject");
+ if (mState == State.RINGING) {
+ onReject();
+ }
+ }
+
+ /**
+ * Inform this Connection that the state of its audio output has been changed externally.
+ *
+ * @param state The new audio state.
+ */
+ public void setAudioState(CallAudioState state) {
+ Log.d(TAG, "setAudioState " + state);
+ onSetAudioState(state);
+ }
+
+ /**
+ * @param state An integer value from {@link State}.
+ * @return A string representation of the value.
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case State.NEW:
+ return "NEW";
+ case State.RINGING:
+ return "RINGING";
+ case State.DIALING:
+ return "DIALING";
+ case State.ACTIVE:
+ return "ACTIVE";
+ case State.HOLDING:
+ return "HOLDING";
+ case State.DISCONNECTED:
+ return "DISCONNECTED";
+ default:
+ Log.wtf(TAG, "Unknown state " + state);
+ return "UNKNOWN";
+ }
+ }
+
+ /**
+ * Sets the value of the {@link #getHandle()} property and notifies listeners.
+ *
+ * @param handle The new handle.
+ */
+ protected void setHandle(Uri handle) {
+ Log.d(TAG, "setHandle " + handle);
+ // TODO: Enforce super called
+ mHandle = handle;
+ for (Listener l : mListeners) {
+ l.onHandleChanged(this, handle);
+ }
+ }
+
+ /**
+ * Sets state to active (e.g., an ongoing call where two or more parties can actively
+ * communicate).
+ */
+ protected void setActive() {
+ setState(State.ACTIVE);
+ }
+
+ /**
+ * Sets state to ringing (e.g., an inbound ringing call).
+ */
+ protected void setRinging() {
+ setState(State.RINGING);
+ }
+
+ /**
+ * Sets state to dialing (e.g., dialing an outbound call).
+ */
+ protected void setDialing() {
+ setState(State.DIALING);
+ }
+
+ /**
+ * Sets state to be on hold.
+ */
+ protected void setOnHold() {
+ setState(State.HOLDING);
+ }
+
+ /**
+ * Sets state to disconnected. This will first notify listeners with an
+ * {@link Listener#onStateChanged(Connection, int)} event, then will fire an
+ * {@link Listener#onDisconnected(Connection, int, String)} event with additional
+ * details.
+ *
+ * @param cause The reason for the disconnection, any of
+ * {@link android.telephony.DisconnectCause}.
+ * @param message Optional call-service-provided message about the disconnect.
+ */
+ protected void setDisconnected(int cause, String message) {
+ setState(State.DISCONNECTED);
+ Log.d(TAG, "Disconnected with cause " + cause + " message " + message);
+ for (Listener l : mListeners) {
+ l.onDisconnected(this, cause, message);
+ }
+ }
+
+ /**
+ * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
+ * has a new value.
+ *
+ * @param state The new call audio state.
+ */
+ protected void onSetAudioState(CallAudioState state) {
+ // TODO: Enforce super called
+ this.mCallAudioState = state;
+ for (Listener l : mListeners) {
+ l.onAudioStateChanged(this, state);
+ }
+ }
+
+ /**
+ * Notifies this Connection and listeners of a change in the current signal levels
+ * for the underlying data transport.
+ *
+ * @param details A {@link android.os.Bundle} containing details of the current level.
+ */
+ protected void onSetSignal(Bundle details) {
+ // TODO: Enforce super called
+ for (Listener l : mListeners) {
+ l.onSignalChanged(this, details);
+ }
+ }
+
+ /**
+ * Notifies this Connection of a request to play a DTMF tone.
+ *
+ * @param c A DTMF character.
+ */
+ protected void onPlayDtmfTone(char c) {}
+
+ /**
+ * Notifies this Connection of a request to stop any currently playing DTMF tones.
+ */
+ protected void onStopDtmfTone() {}
+
+ /**
+ * Notifies this Connection of a request to disconnect.
+ */
+ protected void onDisconnect() {}
+
+ /**
+ * Notifies this Connection of a request to abort.
+ */
+ protected void onAbort() {}
+
+ /**
+ * Notifies this Connection of a request to hold.
+ */
+ protected void onHold() {}
+
+ /**
+ * Notifies this Connection of a request to exit a hold state.
+ */
+ protected void onUnhold() {}
+
+ /**
+ * Notifies this Connection, which is in {@link State#RINGING}, of
+ * a request to accept.
+ */
+ protected void onAnswer() {}
+
+ /**
+ * Notifies this Connection, which is in {@link State#RINGING}, of
+ * a request to reject.
+ */
+ protected void onReject() {}
+
+ private void setState(int state) {
+ Log.d(TAG, "setState: " + stateToString(state));
+ this.mState = state;
+ for (Listener l : mListeners) {
+ l.onStateChanged(this, state);
+ }
+ }
+}
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
new file mode 100644
index 0000000..c1f1871
--- /dev/null
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.Bundle;
+import android.net.Uri;
+
+/**
+ * Simple data container encapsulating a request to some entity to
+ * create a new {@link Connection}.
+ */
+public final class ConnectionRequest {
+
+ // TODO: Token to limit recursive invocations
+ // TODO: Consider upgrading "mHandle" to ordered list of handles, indicating a set of phone
+ // numbers that would satisfy the client's needs, in order of preference
+ private final Uri mHandle;
+ private final Bundle mExtras;
+
+ public ConnectionRequest(Uri handle, Bundle extras) {
+ mHandle = handle; mExtras = extras;
+ }
+
+ /**
+ * The handle (e.g., phone number) to which the {@link Connection} is to connect.
+ */
+ public Uri getHandle() { return mHandle; }
+
+ /**
+ * Application-specific extra data. Used for passing back information from an incoming
+ * call {@code Intent}, and for any proprietary extensions arranged between a client
+ * and servant {@code ConnectionService} which agree on a vocabulary for such data.
+ */
+ public Bundle getExtras() { return mExtras; }
+
+ public String toString() {
+ return String.format("PhoneConnectionRequest %s %s",
+ mHandle == null
+ ? Uri.EMPTY
+ : ConnectionService.toLogSafePhoneNumber(mHandle.toString()),
+ mExtras == null ? "" : mExtras);
+ }
+}
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
new file mode 100644
index 0000000..aba4579
--- /dev/null
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -0,0 +1,345 @@
+/*
+ * 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.Bundle;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link android.app.Service} that provides telephone connections to
+ * processes running on an Android device.
+ */
+public abstract class ConnectionService extends CallService {
+ private static final String TAG = ConnectionService.class.getSimpleName();
+
+ // STOPSHIP: Debug Logging should be conditional on a debug flag or use a set of
+ // logging functions that make it automaticaly so.
+
+ // Flag controlling whether PII is emitted into the logs
+ private static final boolean PII_DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final Connection NULL_CONNECTION = new Connection() {};
+
+ // Mappings from Connections to IDs as understood by the current CallService implementation
+ private final Map<String, Connection> mConnectionById = new HashMap<>();
+ private final Map<Connection, String> mIdByConnection = new HashMap<>();
+
+ private final Connection.Listener mConnectionListener = new Connection.Listener() {
+ @Override
+ public void onStateChanged(Connection c, int state) {
+ String id = mIdByConnection.get(c);
+ Log.d(TAG, "Adapter set state " + id + " " + Connection.stateToString(state));
+ switch (state) {
+ case Connection.State.ACTIVE:
+ getAdapter().setActive(id);
+ break;
+ case Connection.State.DIALING:
+ getAdapter().setDialing(id);
+ break;
+ case Connection.State.DISCONNECTED:
+ // Handled in onDisconnected()
+ break;
+ case Connection.State.HOLDING:
+ getAdapter().setOnHold(id);
+ break;
+ case Connection.State.NEW:
+ // Nothing to tell Telecomm
+ break;
+ case Connection.State.RINGING:
+ getAdapter().setRinging(id);
+ break;
+ }
+ }
+
+ @Override
+ public void onDisconnected(Connection c, int cause, String message) {
+ String id = mIdByConnection.get(c);
+ Log.d(TAG, "Adapter set disconnected " + cause + " " + message);
+ getAdapter().setDisconnected(id, cause, message);
+ }
+
+ @Override
+ public void onHandleChanged(Connection c, Uri newHandle) {
+ // TODO: Unsupported yet
+ }
+
+ @Override
+ public void onAudioStateChanged(Connection c, CallAudioState state) {
+ // TODO: Unsupported yet
+ }
+
+ @Override
+ public void onSignalChanged(Connection c, Bundle details) {
+ // TODO: Unsupported yet
+ }
+
+ @Override
+ public void onDestroyed(Connection c) {
+ removeConnection(c);
+ }
+ };
+
+ @Override
+ public final void isCompatibleWith(final CallInfo callInfo) {
+ Log.d(TAG, "isCompatibleWith " + callInfo);
+ onFindSubscriptions(
+ callInfo.getHandle(),
+ new Response<Uri, Subscription>() {
+ @Override
+ public void onResult(Uri handle, Subscription... result) {
+ boolean isCompatible = result.length > 0;
+ Log.d(TAG, "adapter setIsCompatibleWith "
+ + callInfo.getId() + " " + isCompatible);
+ getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
+ }
+
+ @Override
+ public void onError(Uri handle, String reason) {
+ Log.wtf(TAG, "Error in onFindSubscriptions " + callInfo.getHandle()
+ + " error: " + reason);
+ getAdapter().setIsCompatibleWith(callInfo.getId(), false);
+ }
+ }
+ );
+ }
+
+ @Override
+ public final void call(final CallInfo callInfo) {
+ Log.d(TAG, "call " + callInfo);
+ onCreateConnections(
+ new ConnectionRequest(
+ callInfo.getHandle(),
+ callInfo.getExtras()),
+ new Response<ConnectionRequest, Connection>() {
+ @Override
+ public void onResult(ConnectionRequest request, Connection... result) {
+ if (result.length != 1) {
+ Log.d(TAG, "adapter handleFailedOutgoingCall " + callInfo);
+ getAdapter().handleFailedOutgoingCall(
+ callInfo.getId(),
+ "Created " + result.length + " Connections, expected 1");
+ for (Connection c : result) {
+ c.abort();
+ }
+ } else {
+ addConnection(callInfo.getId(), result[0]);
+ Log.d(TAG, "adapter handleSuccessfulOutgoingCall "
+ + callInfo.getId());
+ getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+ }
+ }
+
+ @Override
+ public void onError(ConnectionRequest request, String reason) {
+ getAdapter().handleFailedOutgoingCall(callInfo.getId(), reason);
+ }
+ }
+ );
+ }
+
+ @Override
+ public final void abort(String callId) {
+ Log.d(TAG, "abort " + callId);
+ findConnectionForAction(callId, "abort").abort();
+ }
+
+ @Override
+ public final void setIncomingCallId(final String callId, Bundle extras) {
+ Log.d(TAG, "setIncomingCallId " + callId + " " + extras);
+ onCreateIncomingConnection(
+ new ConnectionRequest(
+ null, // TODO: Can we obtain this from "extras"?
+ extras),
+ new Response<ConnectionRequest, Connection>() {
+ @Override
+ public void onResult(ConnectionRequest request, Connection... result) {
+ if (result.length != 1) {
+ Log.d(TAG, "adapter handleFailedOutgoingCall " + callId);
+ getAdapter().handleFailedOutgoingCall(
+ callId,
+ "Created " + result.length + " Connections, expected 1");
+ for (Connection c : result) {
+ c.abort();
+ }
+ } else {
+ addConnection(callId, result[0]);
+ Log.d(TAG, "adapter notifyIncomingCall " + callId);
+ // TODO: Uri.EMPTY is because CallInfo crashes when Parceled with a
+ // null URI ... need to fix that at its cause!
+ getAdapter().notifyIncomingCall(new CallInfo(
+ callId,
+ connectionStateToCallState(result[0].getState()),
+ request.getHandle() /* result[0].getHandle() == null
+ ? Uri.EMPTY : result[0].getHandle() */));
+ }
+ }
+
+ @Override
+ public void onError(ConnectionRequest request, String reason) {
+ Log.d(TAG, "adapter failed setIncomingCallId " + request + " " + reason);
+ }
+ }
+ );
+ }
+
+ @Override
+ public final void answer(String callId) {
+ Log.d(TAG, "answer " + callId);
+ findConnectionForAction(callId, "answer").answer();
+ }
+
+ @Override
+ public final void reject(String callId) {
+ Log.d(TAG, "reject " + callId);
+ findConnectionForAction(callId, "reject").reject();
+ }
+
+ @Override
+ public final void disconnect(String callId) {
+ Log.d(TAG, "disconnect " + callId);
+ findConnectionForAction(callId, "disconnect").disconnect();
+ }
+
+ @Override
+ public final void hold(String callId) {
+ Log.d(TAG, "hold " + callId);
+ findConnectionForAction(callId, "hold").hold();
+ }
+
+ @Override
+ public final void unhold(String callId) {
+ Log.d(TAG, "unhold " + callId);
+ findConnectionForAction(callId, "unhold").unhold();
+ }
+
+ @Override
+ public final void playDtmfTone(String callId, char digit) {
+ Log.d(TAG, "playDtmfTone " + callId + " " + Character.toString(digit));
+ findConnectionForAction(callId, "playDtmfTone").playDtmfTone(digit);
+ }
+
+ @Override
+ public final void stopDtmfTone(String callId) {
+ Log.d(TAG, "stopDtmfTone " + callId);
+ findConnectionForAction(callId, "stopDtmfTone").stopDtmfTone();
+ }
+
+ @Override
+ public final void onAudioStateChanged(String callId, CallAudioState audioState) {
+ Log.d(TAG, "onAudioStateChanged " + callId + " " + audioState);
+ findConnectionForAction(callId, "onAudioStateChanged").setAudioState(audioState);
+ }
+
+ /**
+ * Find a set of Subscriptions matching a given handle (e.g. phone number).
+ *
+ * @param handle A handle (e.g. phone number) with which to connect.
+ * @param callback A callback for providing the result.
+ */
+ public void onFindSubscriptions(
+ Uri handle,
+ Response<Uri, Subscription> callback) {}
+
+ /**
+ * Create a Connection given a request.
+ *
+ * @param request Data encapsulating details of the desired Connection.
+ * @param callback A callback for providing the result.
+ */
+ public void onCreateConnections(
+ ConnectionRequest request,
+ Response<ConnectionRequest, Connection> callback) {}
+
+ /**
+ * Create a Connection to match an incoming connection notification.
+ *
+ * @param request Data encapsulating details of the desired Connection.
+ * @param callback A callback for providing the result.
+ */
+ public void onCreateIncomingConnection(
+ ConnectionRequest request,
+ Response<ConnectionRequest, Connection> callback) {}
+
+ static String toLogSafePhoneNumber(String number) {
+ // For unknown number, log empty string.
+ if (number == null) {
+ return "";
+ }
+
+ if (PII_DEBUG) {
+ // When PII_DEBUG is true we emit PII.
+ return number;
+ }
+
+ // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
+ // sanitized phone numbers.
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < number.length(); i++) {
+ char c = number.charAt(i);
+ if (c == '-' || c == '@' || c == '.') {
+ builder.append(c);
+ } else {
+ builder.append('x');
+ }
+ }
+ return builder.toString();
+ }
+
+ private CallState connectionStateToCallState(int connectionState) {
+ switch (connectionState) {
+ case Connection.State.NEW:
+ return CallState.NEW;
+ case Connection.State.RINGING:
+ return CallState.RINGING;
+ case Connection.State.DIALING:
+ return CallState.DIALING;
+ case Connection.State.ACTIVE:
+ return CallState.ACTIVE;
+ case Connection.State.HOLDING:
+ return CallState.ON_HOLD;
+ case Connection.State.DISCONNECTED:
+ return CallState.DISCONNECTED;
+ default:
+ Log.wtf(TAG, "Unknown Connection.State " + connectionState);
+ return CallState.NEW;
+ }
+ }
+
+ private void addConnection(String callId, Connection connection) {
+ mConnectionById.put(callId, connection);
+ mIdByConnection.put(connection, callId);
+ connection.addConnectionListener(mConnectionListener);
+ }
+
+ private void removeConnection(Connection connection) {
+ connection.removeConnectionListener(mConnectionListener);
+ mConnectionById.remove(mIdByConnection.get(connection));
+ mIdByConnection.remove(connection);
+ }
+
+ private Connection findConnectionForAction(String callId, String action) {
+ if (mConnectionById.containsKey(callId)) {
+ return mConnectionById.get(callId);
+ }
+ Log.wtf(TAG, action + " - Cannot find Connection \"" + callId + "\"");
+ return NULL_CONNECTION;
+ }
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/Response.java b/telecomm/java/android/telecomm/Response.java
new file mode 100644
index 0000000..14f8340
--- /dev/null
+++ b/telecomm/java/android/telecomm/Response.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * Used to inform a client of asynchronously returned results.
+ */
+public interface Response<IN, OUT> {
+
+ /**
+ * Provide a set of results.
+ *
+ * @param request The original request.
+ * @param result The results.
+ */
+ void onResult(IN request, OUT... result);
+
+ /**
+ * Indicates the inability to provide results.
+ *
+ * @param request The original request.
+ * @param reason The reason for the failure.
+ */
+ void onError(IN request, String reason);
+}
diff --git a/telecomm/java/android/telecomm/Subscription.java b/telecomm/java/android/telecomm/Subscription.java
new file mode 100644
index 0000000..f187f4d
--- /dev/null
+++ b/telecomm/java/android/telecomm/Subscription.java
@@ -0,0 +1,48 @@
+/*
+ * 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.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a distinct subscription, line of service or call placement method that
+ * a {@link ConnectionService} can use to place phone calls.
+ */
+public class Subscription implements Parcelable {
+
+ public Subscription() {}
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {}
+
+ public static final Parcelable.Creator<Subscription> CREATOR
+ = new Parcelable.Creator<Subscription>() {
+ public Subscription createFromParcel(Parcel in) {
+ return new Subscription(in);
+ }
+
+ public Subscription[] newArray(int size) {
+ return new Subscription[size];
+ }
+ };
+
+ private Subscription(Parcel in) {}
+}
diff --git a/telephony/java/android/telephony/CallStateListener.java b/telephony/java/android/telephony/CallStateListener.java
deleted file mode 100644
index e2ffbfa..0000000
--- a/telephony/java/android/telephony/CallStateListener.java
+++ /dev/null
@@ -1,36 +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.telephony;
-
-import android.annotation.PrivateApi;
-
-/** @hide */
-@PrivateApi
-public interface CallStateListener {
- /**
- * Notify of a new or updated call.
- * Any time the state of a call is updated, it will alert any listeners. This includes changes
- * of state such as when a call is put on hold or conferenced.
- *
- * @param callId a unique ideCntifier for a given call that can be used to track state changes
- * @param state the new state of the call.
- * {@see com.android.services.telephony.common.Call$State}
- * @param number the phone number of the call. For some states, this may be blank. However, it
- * will be populated for any initial state.
- */
- public void onCallStateChanged(int callId, int state, String number);
-}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7002744..5d485c5 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -32,7 +32,6 @@
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.ITelephonyListener;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
@@ -82,40 +81,8 @@
static final int NEVER_USE = 2;
}
- private final HashMap<CallStateListener,Listener> mListeners
- = new HashMap<CallStateListener,Listener>();
private final Context mContext;
- private static class Listener extends ITelephonyListener.Stub {
- final CallStateListener mListener;
- private static final int WHAT = 1;
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- mListener.onCallStateChanged(msg.arg1, msg.arg2, (String)msg.obj);
- }
- };
-
- Listener(CallStateListener listener) {
- mListener = listener;
- }
-
- @Override
- public void onUpdate(final int callId, final int state, final String number) {
- if (mHandler != null) {
- mHandler.sendMessage(mHandler.obtainMessage(WHAT, callId, state, number));
- }
- }
-
- void clearQueue() {
- mHandler.removeMessages(WHAT);
-
- // Don't accept more incoming binder calls either.
- mHandler = null;
- }
- }
-
/** @hide */
public TelephonyManager(Context context) {
Context appContext = context.getApplicationContext();
@@ -1773,12 +1740,15 @@
*
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+ *
* @param AID Application id. See ETSI 102.221 and 101.220.
* @return The logical channel id which is negative on error.
*/
public int iccOpenLogicalChannel(String AID) {
try {
- return getITelephony().iccOpenLogicalChannel(AID);
+ return getITelephony().iccOpenLogicalChannel(AID);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -1790,13 +1760,16 @@
*
* Input parameters equivalent to TS 27.007 AT+CCHC command.
*
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+ *
* @param channel is the channel id to be closed as retruned by a successful
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
*/
public boolean iccCloseLogicalChannel(int channel) {
try {
- return getITelephony().iccCloseLogicalChannel(channel);
+ return getITelephony().iccCloseLogicalChannel(channel);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -1808,6 +1781,9 @@
*
* Input parameters equivalent to TS 27.007 AT+CGLA command.
*
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+ *
* @param channel is the channel id to be closed as returned by a successful
* iccOpenLogicalChannel.
* @param cla Class of the APDU command.
@@ -1823,8 +1799,30 @@
public String iccTransmitApduLogicalChannel(int channel, int cla,
int instruction, int p1, int p2, int p3, String data) {
try {
- return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
- instruction, p1, p2, p3, data);
+ return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
+ instruction, p1, p2, p3, data);
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return "";
+ }
+
+ /**
+ * Send ENVELOPE to the SIM and return the response.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+ *
+ * @param content String containing SAT/USAT response in hexadecimal
+ * format starting with command tag. See TS 102 223 for
+ * details.
+ * @return The APDU response from the ICC card, with the last 4 bytes
+ * being the status word. If the command fails, returns an empty
+ * string.
+ */
+ public String sendEnvelopeWithStatus(String content) {
+ try {
+ return getITelephony().sendEnvelopeWithStatus(content);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -2016,46 +2014,6 @@
/** @hide */
@PrivateApi
- public void toggleHold() {
- try {
- getITelephony().toggleHold();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#toggleHold", e);
- }
- }
-
- /** @hide */
- @PrivateApi
- public void merge() {
- try {
- getITelephony().merge();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#merge", e);
- }
- }
-
- /** @hide */
- @PrivateApi
- public void swap() {
- try {
- getITelephony().swap();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#swap", e);
- }
- }
-
- /** @hide */
- @PrivateApi
- public void mute(boolean mute) {
- try {
- getITelephony().mute(mute);
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#mute", e);
- }
- }
-
- /** @hide */
- @PrivateApi
public void silenceRinger() {
try {
getITelephony().silenceRinger();
@@ -2291,56 +2249,4 @@
}
return false;
}
-
- /** @hide */
- @PrivateApi
- public void playDtmfTone(char digit, boolean timedShortCode) {
- try {
- getITelephony().playDtmfTone(digit, timedShortCode);
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#playDtmfTone", e);
- }
- }
-
- /** @hide */
- @PrivateApi
- public void stopDtmfTone() {
- try {
- getITelephony().stopDtmfTone();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#stopDtmfTone", e);
- }
- }
-
- /** @hide */
- @PrivateApi
- public void addCallStateListener(CallStateListener listener) {
- try {
- if (listener == null) {
- throw new RuntimeException("Listener can't be null");
- }
- if (!mListeners.containsKey(listener)) {
- final Listener l = new Listener(listener);
- mListeners.put(listener, l);
- getITelephony().addListener(l);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#addListener", e);
- }
- }
-
- /** @hide */
- @PrivateApi
- public void removeCallStateListener(CallStateListener listener) {
- try {
- final Listener l = mListeners.remove(listener);
- if (l != null) {
- // Make sure that no callbacks that are already in flight come.
- l.clearQueue();
- getITelephony().removeListener(l);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#removeListener", e);
- }
- }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 72398ad..baacb74 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -21,8 +21,6 @@
import android.telephony.CellInfo;
import android.telephony.NeighboringCellInfo;
-import com.android.internal.telephony.ITelephonyListener;
-
import java.util.List;
import java.util.List;
@@ -373,6 +371,18 @@
int p1, int p2, int p3, String data);
/**
+ * Send ENVELOPE to the SIM and returns the response.
+ *
+ * @param contents String containing SAT/USAT response in hexadecimal
+ * format starting with command tag. See TS 102 223 for
+ * details.
+ * @return The APDU response from the ICC card, with the last 4 bytes
+ * being the status word. If the command fails, returns an empty
+ * string.
+ */
+ String sendEnvelopeWithStatus(String content);
+
+ /**
* Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
* Used for device configuration by some CDMA operators.
*
@@ -426,47 +436,4 @@
* @return true on success; false on any failure.
*/
boolean setPreferredNetworkType(int networkType);
-
- /**
- * Put a call on hold.
- */
- void toggleHold();
-
- /**
- * Merge foreground and background calls.
- */
- void merge();
-
- /**
- * Swap foreground and background calls.
- */
- void swap();
-
- /**
- * Mute the phone.
- */
- void mute(boolean mute);
-
- /**
- * Start playing DTMF tone for the specified digit.
- *
- * @param digit the digit that corresponds with the desired tone.
- * @param timedShortcode whether the specified digit should be played as a timed short code.
- */
- void playDtmfTone(char digit, boolean timedShortCode);
-
- /**
- * Stop playing DTMF tones.
- */
- void stopDtmfTone();
-
- /**
- * Register a callback.
- */
- void addListener(ITelephonyListener listener);
-
- /**
- * Unregister a callback.
- */
- void removeListener(ITelephonyListener listener);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl b/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
deleted file mode 100644
index c226217..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
+++ /dev/null
@@ -1,27 +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.telephony;
-
-/**
- * Interface used to register a listener that gets more detailed call state information than
- * {@link android.telephony.PhoneStateListener}
- *
- * {@hide}
- */
-oneway interface ITelephonyListener {
- void onUpdate(int callId, int state, String number);
-}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0d9cd18..c162bf28 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -350,7 +350,17 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
@Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ Handler scheduler,
+ int initialCode, String initialData, Bundle initialExtras) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+
public void sendStickyBroadcast(Intent intent) {
throw new UnsupportedOperationException();
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
index e4ea9367..5b0aa66 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -130,7 +130,8 @@
RenderNodeAnimator anim = mRunningAnimations.get(i);
anim.setInterpolator(interp);
anim.setDuration(1000);
- anim.start(this);
+ anim.setTarget(this);
+ anim.start();
}
if (mToggle) {
@@ -146,7 +147,6 @@
}
});
}
-
return true;
}
}
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
index 189fa6a..2b14384 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
@@ -15,8 +15,8 @@
package com.android.onemedia;
-import android.media.session.SessionToken;
+import android.media.session.MediaSessionToken;
interface IPlayerCallback {
- void onSessionChanged(in SessionToken session);
+ void onSessionChanged(in MediaSessionToken session);
}
\ No newline at end of file
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
index 15ea25f..efdbe9a 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
@@ -15,14 +15,14 @@
package com.android.onemedia;
-import android.media.session.SessionToken;
+import android.media.session.MediaSessionToken;
import android.os.Bundle;
import com.android.onemedia.IPlayerCallback;
import com.android.onemedia.playback.IRequestCallback;
interface IPlayerService {
- SessionToken getSessionToken();
+ MediaSessionToken getSessionToken();
void registerCallback(in IPlayerCallback cb);
void unregisterCallback(in IPlayerCallback cb);
void sendRequest(String action, in Bundle params, in IRequestCallback cb);
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
index b9a6470..158f5e4 100644
--- a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
+++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
@@ -17,7 +17,7 @@
import android.app.Activity;
-import android.media.session.MediaMetadata;
+import android.media.MediaMetadata;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.util.Log;
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index e3f5c0c..9f7bb26 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -16,10 +16,10 @@
*/
package com.android.onemedia;
-import android.media.session.SessionController;
-import android.media.session.MediaMetadata;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
import android.media.session.RouteInfo;
-import android.media.session.SessionManager;
+import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.media.session.TransportController;
import android.os.Bundle;
@@ -40,7 +40,7 @@
public static final int STATE_DISCONNECTED = 0;
public static final int STATE_CONNECTED = 1;
- protected SessionController mController;
+ protected MediaController mController;
protected IPlayerService mBinder;
protected TransportController mTransportControls;
@@ -49,7 +49,7 @@
private Listener mListener;
private TransportListener mTransportListener = new TransportListener();
private SessionCallback mControllerCb;
- private SessionManager mManager;
+ private MediaSessionManager mManager;
private Handler mHandler = new Handler();
private boolean mResumed;
@@ -62,7 +62,7 @@
mServiceIntent = serviceIntent;
}
mControllerCb = new SessionCallback();
- mManager = (SessionManager) context
+ mManager = (MediaSessionManager) context
.getSystemService(Context.MEDIA_SESSION_SERVICE);
mResumed = false;
@@ -155,7 +155,7 @@
mBinder = IPlayerService.Stub.asInterface(service);
Log.d(TAG, "service is " + service + " binder is " + mBinder);
try {
- mController = SessionController.fromToken(mBinder.getSessionToken());
+ mController = MediaController.fromToken(mBinder.getSessionToken());
} catch (RemoteException e) {
Log.e(TAG, "Error getting session", e);
return;
@@ -176,7 +176,7 @@
}
};
- private class SessionCallback extends SessionController.Callback {
+ private class SessionCallback extends MediaController.Callback {
@Override
public void onRouteChanged(RouteInfo route) {
// TODO
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
index 8b53ddf..0ad6dd1 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
@@ -17,7 +17,7 @@
import android.app.Service;
import android.content.Intent;
-import android.media.session.SessionToken;
+import android.media.session.MediaSessionToken;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.IBinder;
@@ -149,7 +149,7 @@
}
@Override
- public SessionToken getSessionToken() throws RemoteException {
+ public MediaSessionToken getSessionToken() throws RemoteException {
return mSession.getSessionToken();
}
}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index b7dcef7..94d0851 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -21,9 +21,9 @@
import android.media.session.RouteInfo;
import android.media.session.RouteOptions;
import android.media.session.RoutePlaybackControls;
-import android.media.session.Session;
-import android.media.session.SessionManager;
-import android.media.session.SessionToken;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionToken;
import android.media.session.PlaybackState;
import android.media.session.TransportPerformer;
import android.os.Bundle;
@@ -40,10 +40,10 @@
public class PlayerSession {
private static final String TAG = "PlayerSession";
- protected Session mSession;
+ protected MediaSession mSession;
protected Context mContext;
protected Renderer mRenderer;
- protected Session.Callback mCallback;
+ protected MediaSession.Callback mCallback;
protected Renderer.Listener mRenderListener;
protected TransportPerformer mPerformer;
@@ -79,7 +79,7 @@
if (mSession != null) {
mSession.release();
}
- SessionManager man = (SessionManager) mContext
+ MediaSessionManager man = (MediaSessionManager) mContext
.getSystemService(Context.MEDIA_SESSION_SERVICE);
Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
mSession = man.createSession("OneMedia");
@@ -87,7 +87,7 @@
mPerformer = mSession.getTransportPerformer();
mPerformer.addListener(new TransportListener());
mPerformer.setPlaybackState(mPlaybackState);
- mSession.setFlags(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
mSession.setRouteOptions(mRouteOptions);
mSession.setActive(true);
}
@@ -106,7 +106,7 @@
mListener = listener;
}
- public SessionToken getSessionToken() {
+ public MediaSessionToken getSessionToken() {
return mSession.getSessionToken();
}
@@ -204,7 +204,7 @@
}
- private class SessionCb extends Session.Callback {
+ private class SessionCb extends MediaSession.Callback {
@Override
public void onMediaButton(Intent mediaRequestIntent) {
if (Intent.ACTION_MEDIA_BUTTON.equals(mediaRequestIntent.getAction())) {
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
index b5b12d8..c7715ad 100644
--- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
+++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
@@ -77,7 +77,8 @@
RenderNodeAnimator.TRANSLATION_Y, dy * delta);
animator.setDuration(DURATION);
if (child == clickedView) logTranslationY(clickedView);
- animator.start(child);
+ animator.setTarget(child);
+ animator.start();
if (child == clickedView) logTranslationY(clickedView);
}
//mHandler.postDelayed(mLaunchActivity, (long) (DURATION * .4));
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 08e9d99..d31239b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -567,7 +567,7 @@
StyleResourceValue customStyleValues = null;
if (customStyle != null) {
ResourceValue item = mRenderResources.findResValue(customStyle,
- false /*forceFrameworkOnly*/);
+ isPlatformFile /*forceFrameworkOnly*/);
// resolve it in case it links to something else
item = mRenderResources.resolveResValue(item);
@@ -1284,6 +1284,14 @@
}
@Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ Handler scheduler,
+ int initialCode, String initialData, Bundle initialExtras) {
+ // pass
+ }
+
+ @Override
public void sendStickyBroadcast(Intent arg0) {
// pass
diff --git a/tools/layoutlib/rename_font/README b/tools/layoutlib/rename_font/README
new file mode 100644
index 0000000..600b756
--- /dev/null
+++ b/tools/layoutlib/rename_font/README
@@ -0,0 +1,9 @@
+This tool is used to rename the PS name encoded inside the ttf font that we ship
+with the SDK. There is bug in Java that returns incorrect results for
+java.awt.Font#layoutGlyphVector() if two fonts with same name but differnt
+versions are loaded. As a workaround, we rename all the fonts that we ship with
+the SDK by appending the font version to its name.
+
+
+The build_font.py copies all files from input_dir to output_dir while renaming
+the font files (*.ttf) in the process.
diff --git a/tools/layoutlib/rename_font/Roboto-Regular.ttf b/tools/layoutlib/rename_font/Roboto-Regular.ttf
new file mode 100644
index 0000000..7469063
--- /dev/null
+++ b/tools/layoutlib/rename_font/Roboto-Regular.ttf
Binary files differ
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
new file mode 100755
index 0000000..ea3dccc
--- /dev/null
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""
+Rename the PS name of all fonts in the input directory and copy them to the
+output directory.
+
+Usage: build_font.py /path/to/input_fonts/ /path/to/output_fonts/
+
+"""
+
+import sys
+# fontTools is available at platform/external/fonttools
+from fontTools import ttx
+import re
+import os
+from lxml import etree
+import shutil
+import glob
+
+def main(argv):
+ if len(argv) != 2:
+ print "Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/"
+ sys.exit(1)
+ if not os.path.isdir(argv[0]):
+ print argv[0] + "is not a valid directory"
+ sys.exit(1)
+ if not os.path.isdir(argv[1]):
+ print argv[1] + "is not a valid directory"
+ sys.exit(1)
+ cwd = os.getcwd()
+ os.chdir(argv[1])
+ files = glob.glob('*')
+ for filename in files:
+ os.remove(filename)
+ os.chdir(cwd)
+ for filename in os.listdir(argv[0]):
+ if not os.path.splitext(filename)[1].lower() == ".ttf":
+ shutil.copy(os.path.join(argv[0], filename), argv[1])
+ continue
+ print os.path.join(argv[0], filename)
+ old_ttf_path = os.path.join(argv[0], filename)
+ # run ttx to generate an xml file in the output folder which represents all
+ # its info
+ ttx_args = ["-d", argv[1], old_ttf_path]
+ ttx.main(ttx_args)
+ # the path to the output file. The file name is the fontfilename.ttx
+ ttx_path = os.path.join(argv[1], filename)
+ ttx_path = ttx_path[:-1] + "x"
+ # now parse the xml file to change its PS name.
+ tree = etree.parse(ttx_path)
+ encoding = tree.docinfo.encoding
+ root = tree.getroot()
+ for name in root.iter('name'):
+ [old_ps_name, version] = get_font_info(name)
+ new_ps_name = old_ps_name + version
+ update_name(name, new_ps_name)
+ tree.write(ttx_path, xml_declaration=True, encoding=encoding )
+ # generate the udpated font now.
+ ttx_args = ["-d", argv[1], ttx_path]
+ ttx.main(ttx_args)
+ # delete the temp ttx file.
+ os.remove(ttx_path)
+
+def get_font_info(tag):
+ ps_name = None
+ ps_version = None
+ for namerecord in tag.iter('namerecord'):
+ if 'nameID' in namerecord.attrib:
+ # if the tag has nameID=6, it is the postscript name of the font.
+ # see: http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
+ if namerecord.attrib['nameID'] == '6':
+ if ps_name is not None:
+ if not sanitize(namerecord.text) == ps_name:
+ sys.exit('found multiple possibilities of the font name')
+ else:
+ ps_name = sanitize(namerecord.text)
+ # nameID=5 means the font version
+ if namerecord.attrib['nameID'] == '5':
+ if ps_version is not None:
+ if not ps_version == get_version(namerecord.text):
+ sys.exit('found multiple possibilities of the font version')
+ else:
+ ps_version = get_version(namerecord.text)
+ if ps_name is not None and ps_version is not None:
+ return [ps_name, ps_version]
+ sys.exit('didn\'t find the font name or version')
+
+
+def update_name(tag, name):
+ for namerecord in tag.iter('namerecord'):
+ if 'nameID' in namerecord.attrib:
+ if namerecord.attrib['nameID'] == '6':
+ namerecord.text = name
+
+def sanitize(string):
+ return re.sub(r'[^\w-]+', '', string)
+
+def get_version(string):
+ # The string must begin with "Version n.nn "
+ # to extract n.nn, we return the second entry in the split strings.
+ string = string.strip()
+ if not string.startswith("Version "):
+ sys.exit('mal-formed font version')
+ return sanitize(string.split()[1])
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
new file mode 100755
index 0000000..d4c86cb
--- /dev/null
+++ b/tools/layoutlib/rename_font/test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+"""Tests build_font.py by renaming a font.
+
+The test copies Roboto-Regular.ttf to a tmp directory and ask build_font.py to rename it and put in another dir.
+We then use ttx to dump the new font to its xml and check if rename was successful
+
+To test locally, use:
+PYTHONPATH="$PYTHONPATH:/path/to/android/checkout/external/fonttools/Lib" ./test.py
+"""
+
+import unittest
+import build_font
+
+from fontTools import ttx
+import os
+from lxml import etree
+import shutil
+import tempfile
+
+class MyTest(unittest.TestCase):
+ def test(self):
+ font_name = "Roboto-Regular.ttf"
+ srcdir = tempfile.mkdtemp()
+ print "srcdir: " + srcdir
+ shutil.copy(font_name, srcdir)
+ destdir = tempfile.mkdtemp()
+ print "destdir: " + destdir
+ self.assertTrue(build_font.main([srcdir, destdir]) is None)
+ out_path = os.path.join(destdir, font_name)
+ ttx.main([out_path])
+ ttx_path = out_path[:-1] + "x"
+ tree = etree.parse(ttx_path)
+ root = tree.getroot()
+ name_tag = root.find('name')
+ [f_name, f_version] = build_font.get_font_info(name_tag)
+ shutil.rmtree(srcdir)
+ shutil.rmtree(destdir)
+ self.assertEqual(f_name, "Roboto-Regular1200310")
+
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0535fe0..9ccd810 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -111,8 +111,6 @@
Messenger getWifiServiceMessenger();
- Messenger getWifiStateMachineMessenger();
-
String getConfigFile();
void enableTdls(String remoteIPAddress, boolean enable);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 1cb9546..3e3b6e3 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,6 +16,8 @@
package android.net.wifi;
+import android.net.wifi.passpoint.PasspointInfo;
+import android.net.wifi.passpoint.PasspointManager;
import android.os.Parcelable;
import android.os.Parcel;
@@ -77,6 +79,13 @@
public int distanceSdCm;
/**
+ * Passpoint ANQP information. This is not fetched automatically.
+ * Use {@link PasspointManager#requestAnqpInfo} to request ANQP info.
+ * {@hide}
+ */
+ public PasspointInfo passpoint;
+
+ /**
* {@hide}
*/
public final static int UNSPECIFIED = -1;
@@ -122,6 +131,8 @@
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
seen = source.seen;
+ if (source.passpoint != null)
+ passpoint = new PasspointInfo(source.passpoint);
}
}
@@ -155,6 +166,9 @@
sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
append("(cm)");
+ if (passpoint != null)
+ sb.append(", passpoint: [").append(passpoint.toString()).append("]");
+
return sb.toString();
}
@@ -178,6 +192,12 @@
dest.writeLong(timestamp);
dest.writeInt(distanceCm);
dest.writeInt(distanceSdCm);
+ if (passpoint != null) {
+ dest.writeInt(1);
+ passpoint.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
}
/** Implement the Parcelable interface {@hide} */
@@ -188,7 +208,7 @@
if (in.readInt() == 1) {
wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
}
- return new ScanResult(
+ ScanResult sr = new ScanResult(
wifiSsid,
in.readString(),
in.readString(),
@@ -198,6 +218,10 @@
in.readInt(),
in.readInt()
);
+ if (in.readInt() == 1) {
+ sr.passpoint = PasspointInfo.CREATOR.createFromParcel(in);
+ }
+ return sr;
}
public ScanResult[] newArray(int size) {
diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
new file mode 100644
index 0000000..922eddd
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
@@ -0,0 +1,189 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+import java.util.HashMap;
+import java.util.Date;
+import java.util.ArrayList;
+
+import java.util.BitSet;
+
+/**
+ * A class representing link layer statistics collected over a Wifi Interface.
+ */
+/** {@hide} */
+public class WifiLinkLayerStats implements Parcelable {
+ private static final String TAG = "WifiLinkLayerStats";
+
+ /**
+ * The current status of this network configuration entry.
+ * @see Status
+ */
+ /** {@hide} */
+ public int status;
+
+ /**
+ * The network's SSID. Can either be an ASCII string,
+ * which must be enclosed in double quotation marks
+ * (e.g., {@code "MyNetwork"}, or a string of
+ * hex digits,which are not enclosed in quotes
+ * (e.g., {@code 01a243f405}).
+ */
+ /** {@hide} */
+ public String SSID;
+ /**
+ * When set. this is the BSSID the radio is currently associated with.
+ * The value is a string in the format of an Ethernet MAC address, e.g.,
+ * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
+ */
+ /** {@hide} */
+ public String BSSID;
+
+ /* number beacons received from our own AP */
+ /** {@hide} */
+ public int beacon_rx;
+
+ /* RSSI taken on management frames */
+ /** {@hide} */
+ public int rssi_mgmt;
+
+ /* packets counters */
+ /** {@hide} */
+ /* WME Best Effort Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries)*/
+ public long rxmpdu_be;
+ /** {@hide} */
+ public long txmpdu_be;
+ /** {@hide} */
+ public long lostmpdu_be;
+ /** {@hide} */
+ public long retries_be;
+ /** {@hide} */
+ /* WME Background Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
+ public long rxmpdu_bk;
+ /** {@hide} */
+ public long txmpdu_bk;
+ /** {@hide} */
+ public long lostmpdu_bk;
+ /** {@hide} */
+ public long retries_bk;
+ /** {@hide} */
+ /* WME Video Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
+ public long rxmpdu_vi;
+ /** {@hide} */
+ public long txmpdu_vi;
+ /** {@hide} */
+ public long lostmpdu_vi;
+ /** {@hide} */
+ public long retries_vi;
+ /** {@hide} */
+ /* WME Voice Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
+ public long rxmpdu_vo;
+ /** {@hide} */
+ public long txmpdu_vo;
+ /** {@hide} */
+ public long lostmpdu_vo;
+ /** {@hide} */
+ public long retries_vo;
+
+
+ /** {@hide} */
+ public WifiLinkLayerStats() {
+ }
+
+ @Override
+ /** {@hide} */
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ if (this.SSID != null) {
+ sbuf.append(" SSID: ").append(this.SSID).append('\n');
+ }
+ if (this.BSSID != null) {
+ sbuf.append(" BSSID: ").append(this.BSSID).append('\n');
+ }
+
+ sbuf.append(" my bss beacon rx: ").append(Integer.toString(this.beacon_rx)).append('\n');
+ sbuf.append(" RSSI mgmt: ").append(Integer.toString(this.rssi_mgmt)).append('\n');
+ sbuf.append(" BE : ").append(" rx=").append(Long.toString(this.rxmpdu_be))
+ .append(" tx=").append(Long.toString(this.txmpdu_be))
+ .append(" lost=").append(Long.toString(this.lostmpdu_be))
+ .append(" retries=").append(Long.toString(this.retries_be)).append('\n');
+ sbuf.append(" BK : ").append(" rx=").append(Long.toString(this.rxmpdu_bk))
+ .append(" tx=").append(Long.toString(this.txmpdu_bk))
+ .append(" lost=").append(Long.toString(this.lostmpdu_bk))
+ .append(" retries=").append(Long.toString(this.retries_bk)).append('\n');
+ sbuf.append(" VI : ").append(" rx=").append(Long.toString(this.rxmpdu_vi))
+ .append(" tx=").append(Long.toString(this.txmpdu_vi))
+ .append(" lost=").append(Long.toString(this.lostmpdu_vi))
+ .append(" retries=").append(Long.toString(this.retries_vi)).append('\n');
+ sbuf.append(" VO : ").append(" rx=").append(Long.toString(this.rxmpdu_vo))
+ .append(" tx=").append(Long.toString(this.txmpdu_vo))
+ .append(" lost=").append(Long.toString(this.lostmpdu_vo))
+ .append(" retries=").append(Long.toString(this.retries_vo)).append('\n');
+
+ return sbuf.toString();
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@hide} */
+ public String getPrintableSsid() {
+ if (SSID == null) return "";
+ final int length = SSID.length();
+ if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
+ return SSID.substring(1, length - 1);
+ }
+
+ /** The ascii-encoded string format is P"<ascii-encoded-string>"
+ * The decoding is implemented in the supplicant for a newly configured
+ * network.
+ */
+ if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
+ (SSID.charAt(length-1) == '"')) {
+ WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
+ SSID.substring(2, length - 1));
+ return wifiSsid.toString();
+ }
+ return SSID;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(SSID);
+ dest.writeString(BSSID);
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<WifiLinkLayerStats> CREATOR =
+ new Creator<WifiLinkLayerStats>() {
+ public WifiLinkLayerStats createFromParcel(Parcel in) {
+ WifiLinkLayerStats stats = new WifiLinkLayerStats();
+ stats.SSID = in.readString();
+ stats.BSSID = in.readString();
+ return stats;
+ };
+ public WifiLinkLayerStats[] newArray(int size) {
+ return new WifiLinkLayerStats[size];
+ }
+
+ };
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 15b65c1..9558d50 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1783,18 +1783,6 @@
}
}
- /**
- * Get a reference to WifiStateMachine handler.
- * @return Messenger pointing to the WifiService handler
- * @hide
- */
- public Messenger getWifiStateMachineMessenger() {
- try {
- return mService.getWifiStateMachineMessenger();
- } catch (RemoteException e) {
- return null;
- }
- }
/**
* Returns the file in which IP and proxy configuration data is stored
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index e02e14c..b766268 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -31,7 +31,6 @@
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -41,27 +40,45 @@
* Get an instance of this class by calling
* {@link android.content.Context#getSystemService(String) Context.getSystemService(Context
* .WIFI_SCANNING_SERVICE)}.
- * @hide
*/
public class WifiScanner {
+ /** no band specified; use channel list instead */
public static final int WIFI_BAND_UNSPECIFIED = 0; /* not specified */
+
+ /** 2.4 GHz band */
public static final int WIFI_BAND_24_GHZ = 1; /* 2.4 GHz band */
+ /** 5 GHz band excluding DFS channels */
public static final int WIFI_BAND_5_GHZ = 2; /* 5 GHz band without DFS channels */
+ /** DFS channels from 5 GHz band only */
public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; /* 5 GHz band with DFS channels */
+ /** 5 GHz band including DFS channels */
public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; /* 5 GHz band with DFS channels */
+ /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
public static final int WIFI_BAND_BOTH = 3; /* both bands without DFS channels */
+ /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
public static final int WIFI_BAND_BOTH_WITH_DFS = 7; /* both bands with DFS channels */
- public static final int MIN_SCAN_PERIOD_MS = 300; /* minimum supported period */
+ /** Minimum supported scanning period */
+ public static final int MIN_SCAN_PERIOD_MS = 2000; /* minimum supported period */
+ /** Maximum supported scanning period */
public static final int MAX_SCAN_PERIOD_MS = 1024000; /* maximum supported period */
+ /** No Error */
public static final int REASON_SUCCEEDED = 0;
+ /** Unknown error */
public static final int REASON_UNSPECIFIED = -1;
+ /** Invalid listener */
public static final int REASON_INVALID_LISTENER = -2;
+ /** Invalid request */
public static final int REASON_INVALID_REQUEST = -3;
+ /** Request conflicts with other scans that may be going on */
public static final int REASON_CONFLICTING_REQUEST = -4;
+ /**
+ * Generic action callback invocation interface
+ * @hide
+ */
public static interface ActionListener {
public void onSuccess(Object result);
public void onFailure(int reason, Object exception);
@@ -70,19 +87,35 @@
/**
* gives you all the possible channels; channel is specified as an
* integer with frequency in MHz i.e. channel 1 is 2412
+ * @hide
*/
public List<Integer> getAvailableChannels(int band) {
return null;
}
/**
- * provides channel specification to the APIs
+ * provides channel specification for scanning
*/
public static class ChannelSpec {
+ /**
+ * channel frequency in KHz; for example channel 1 is specified as 2412
+ */
public int frequency;
+ /**
+ * if true, scan this channel in passive fashion.
+ * This flag is ignored on DFS channel specification.
+ * @hide
+ */
public boolean passive; /* ignored on DFS channels */
+ /**
+ * how long to dwell on this channel
+ * @hide
+ */
public int dwellTimeMS; /* not supported for now */
+ /**
+ * default constructor for channel spec
+ */
public ChannelSpec(int frequency) {
this.frequency = frequency;
passive = false;
@@ -90,19 +123,26 @@
}
}
+ /** reports {@link ScanListener#onResults} when underlying buffers are full */
public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
+ /** reports {@link ScanListener#onResults} after each scan */
public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
+ /** reports {@link ScanListener#onFullResult} whenever each beacon is discovered */
public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
/**
- * scan configuration parameters
+ * scan configuration parameters to be sent to {@link #startBackgroundScan}
*/
public static class ScanSettings implements Parcelable {
- public int band; /* ignore channels if specified */
- public ChannelSpec[] channels; /* list of channels to scan */
- public int periodInMs; /* period of scan */
- public int reportEvents; /* a valid REPORT_EVENT value */
+ /** one of the WIFI_BAND values */
+ public int band;
+ /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
+ public ChannelSpec[] channels;
+ /** period of background scan; in millisecond */
+ public int periodInMs;
+ /** must have a valid REPORT_EVENT value */
+ public int reportEvents;
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
@@ -113,6 +153,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(band);
dest.writeInt(periodInMs);
+ dest.writeInt(reportEvents);
dest.writeInt(channels.length);
for (int i = 0; i < channels.length; i++) {
@@ -130,6 +171,7 @@
ScanSettings settings = new ScanSettings();
settings.band = in.readInt();
settings.periodInMs = in.readInt();
+ settings.reportEvents = in.readInt();
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];
for (int i = 0; i < num_channels; i++) {
@@ -151,14 +193,56 @@
}
+ /** information element from beacon */
public static class InformationElement {
public int id;
public byte[] bytes;
}
- public static class FullScanResult {
+ /** scan result with information elements from beacons */
+ public static class FullScanResult implements Parcelable {
public ScanResult result;
public InformationElement informationElements[];
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ result.writeToParcel(dest, flags);
+ dest.writeInt(informationElements.length);
+ for (int i = 0; i < informationElements.length; i++) {
+ dest.writeInt(informationElements[i].id);
+ dest.writeInt(informationElements[i].bytes.length);
+ dest.writeByteArray(informationElements[i].bytes);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<FullScanResult> CREATOR =
+ new Creator<FullScanResult>() {
+ public FullScanResult createFromParcel(Parcel in) {
+ FullScanResult result = new FullScanResult();
+ result.result = ScanResult.CREATOR.createFromParcel(in);
+ int n = in.readInt();
+ result.informationElements = new InformationElement[n];
+ for (int i = 0; i < n; i++) {
+ result.informationElements[i] = new InformationElement();
+ result.informationElements[i].id = in.readInt();
+ int len = in.readInt();
+ result.informationElements[i].bytes = new byte[len];
+ in.readByteArray(result.informationElements[i].bytes);
+ }
+
+ return result;
+ }
+
+ public FullScanResult[] newArray(int size) {
+ return new FullScanResult[size];
+ }
+ };
}
/** @hide */
@@ -206,88 +290,210 @@
}
/**
- * Framework is co-ordinating scans across multiple apps; so it may not give exactly the
- * same period requested. The period granted is stated on the onSuccess() event; and
- * onPeriodChanged() will be called if/when it is changed because of multiple conflicting
- * requests. This is similar to the way timers are handled.
+ * interface to get scan events on; specify this on {@link #startBackgroundScan}
*/
public interface ScanListener extends ActionListener {
+ /**
+ * Framework co-ordinates scans across multiple apps; so it may not give exactly the
+ * same period requested. If period of a scan is changed; it is reported by this event.
+ */
public void onPeriodChanged(int periodInMs);
+ /**
+ * reports results retrieved from background scan
+ */
public void onResults(ScanResult[] results);
+ /**
+ * reports full scan result for each access point found in scan
+ */
public void onFullResult(FullScanResult fullScanResult);
}
+ /** @hide */
public void scan(ScanSettings settings, ScanListener listener) {
validateChannel();
sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings);
}
+
+ /** start wifi scan in background
+ * @param settings specifies various parameters for the scan; for more information look at
+ * {@link ScanSettings}
+ * @param listener specifies the object to report events to. This object is also treated as a
+ * key for this scan, and must also be specified to cancel the scan. Multiple
+ * scans should also not share this object.
+ */
public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
validateChannel();
sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
}
- public void stopBackgroundScan(boolean flush, ScanListener listener) {
+ /**
+ * stop an ongoing wifi scan
+ * @param listener specifies which scan to cancel; must be same object as passed in {@link
+ * #startBackgroundScan}
+ */
+ public void stopBackgroundScan(ScanListener listener) {
validateChannel();
sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
}
+ /**
+ * retrieves currently available scan results
+ * @param flush {@code true} means flush all results
+ * @param listener specifies which scan to cancel; must be same object as passed in {@link
+ * #startBackgroundScan}
+ */
public void retrieveScanResults(boolean flush, ScanListener listener) {
validateChannel();
sAsyncChannel.sendMessage(CMD_GET_SCAN_RESULTS, 0, getListenerKey(listener));
}
+ /** specifies information about an access point of interest */
public static class HotspotInfo {
+ /** bssid of the access point; in XX:XX:XX:XX:XX:XX format */
public String bssid;
+ /** low signal strength threshold; more information at {@link ScanResult#level} */
public int low; /* minimum RSSI */
+ /** high signal threshold; more information at {@link ScanResult#level} */
public int high; /* maximum RSSI */
+ /** channel frequency (in KHz) where you may find this BSSID */
+ public int frequencyHint;
}
- public static class WifiChangeSettings {
- public int rssiSampleSize; /* sample size for RSSI averaging */
- public int lostApSampleSize; /* samples to confirm AP's loss */
- public int unchangedSampleSize; /* samples to confirm no change */
- public int minApsBreachingThreshold; /* change threshold to trigger event */
+ /** @hide */
+ public static class WifiChangeSettings implements Parcelable {
+ public int rssiSampleSize; /* sample size for RSSI averaging */
+ public int lostApSampleSize; /* samples to confirm AP's loss */
+ public int unchangedSampleSize; /* samples to confirm no change */
+ public int minApsBreachingThreshold; /* change threshold to trigger event */
+ public int periodInMs; /* scan period in millisecond */
public HotspotInfo[] hotspotInfos;
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(rssiSampleSize);
+ dest.writeInt(lostApSampleSize);
+ dest.writeInt(unchangedSampleSize);
+ dest.writeInt(minApsBreachingThreshold);
+ dest.writeInt(periodInMs);
+ dest.writeInt(hotspotInfos.length);
+ for (int i = 0; i < hotspotInfos.length; i++) {
+ HotspotInfo info = hotspotInfos[i];
+ dest.writeString(info.bssid);
+ dest.writeInt(info.low);
+ dest.writeInt(info.high);
+ dest.writeInt(info.frequencyHint);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<WifiChangeSettings> CREATOR =
+ new Creator<WifiChangeSettings>() {
+ public WifiChangeSettings createFromParcel(Parcel in) {
+ WifiChangeSettings settings = new WifiChangeSettings();
+ settings.rssiSampleSize = in.readInt();
+ settings.lostApSampleSize = in.readInt();
+ settings.unchangedSampleSize = in.readInt();
+ settings.minApsBreachingThreshold = in.readInt();
+ settings.periodInMs = in.readInt();
+ int len = in.readInt();
+ settings.hotspotInfos = new HotspotInfo[len];
+ for (int i = 0; i < len; i++) {
+ HotspotInfo info = new HotspotInfo();
+ info.bssid = in.readString();
+ info.low = in.readInt();
+ info.high = in.readInt();
+ info.frequencyHint = in.readInt();
+ settings.hotspotInfos[i] = info;
+ }
+ return settings;
+ }
+
+ public WifiChangeSettings[] newArray(int size) {
+ return new WifiChangeSettings[size];
+ }
+ };
+
}
- /* overrides the significant wifi change state machine configuration */
- public void configureSignificantWifiChange(
+ /** configure WifiChange detection
+ * @param rssiSampleSize number of samples used for RSSI averaging
+ * @param lostApSampleSize number of samples to confirm an access point's loss
+ * @param unchangedSampleSize number of samples to confirm there are no changes
+ * @param minApsBreachingThreshold minimum number of access points that need to be
+ * out of range to detect WifiChange
+ * @param periodInMs indicates period of scan to find changes
+ * @param hotspotInfos access points to watch
+ */
+ public void configureWifiChange(
int rssiSampleSize, /* sample size for RSSI averaging */
int lostApSampleSize, /* samples to confirm AP's loss */
int unchangedSampleSize, /* samples to confirm no change */
int minApsBreachingThreshold, /* change threshold to trigger event */
+ int periodInMs, /* period of scan */
HotspotInfo[] hotspotInfos /* signal thresholds to crosss */
)
{
validateChannel();
+
WifiChangeSettings settings = new WifiChangeSettings();
settings.rssiSampleSize = rssiSampleSize;
settings.lostApSampleSize = lostApSampleSize;
settings.unchangedSampleSize = unchangedSampleSize;
settings.minApsBreachingThreshold = minApsBreachingThreshold;
+ settings.periodInMs = periodInMs;
settings.hotspotInfos = hotspotInfos;
- sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+ configureWifiChange(settings);
}
- public interface SignificantWifiChangeListener extends ActionListener {
+ /**
+ * interface to get wifi change events on; use this on {@link #startTrackingWifiChange}
+ */
+ public interface WifiChangeListener extends ActionListener {
+ /** indicates that changes were detected in wifi environment
+ * @param results indicate the access points that exhibited change
+ */
public void onChanging(ScanResult[] results); /* changes are found */
+ /** indicates that no wifi changes are being detected for a while
+ * @param results indicate the access points that are bing monitored for change
+ */
public void onQuiescence(ScanResult[] results); /* changes settled down */
}
- public void trackSignificantWifiChange(SignificantWifiChangeListener listener) {
+ /**
+ * track changes in wifi environment
+ * @param listener object to report events on; this object must be unique and must also be
+ * provided on {@link #stopTrackingWifiChange}
+ */
+ public void startTrackingWifiChange(WifiChangeListener listener) {
validateChannel();
sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
}
- public void untrackSignificantWifiChange(SignificantWifiChangeListener listener) {
+
+ /**
+ * stop tracking changes in wifi environment
+ * @param listener object that was provided to report events on {@link
+ * #stopTrackingWifiChange}
+ */
+ public void stopTrackingWifiChange(WifiChangeListener listener) {
validateChannel();
sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
}
- public void configureSignificantWifiChange(WifiChangeSettings settings) {
+ /** @hide */
+ public void configureWifiChange(WifiChangeSettings settings) {
validateChannel();
sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
}
+ /** interface to receive hotlist events on; use this on {@link #setHotlist} */
public static interface HotlistListener extends ActionListener {
+ /** indicates that access points were found by on going scans
+ * @param results list of scan results, one for each access point visible currently
+ */
public void onFound(ScanResult[] results);
}
@@ -310,6 +516,7 @@
dest.writeString(info.bssid);
dest.writeInt(info.low);
dest.writeInt(info.high);
+ dest.writeInt(info.frequencyHint);
}
}
@@ -326,6 +533,7 @@
info.bssid = in.readString();
info.low = in.readInt();
info.high = in.readInt();
+ info.frequencyHint = in.readInt();
settings.hotspotInfos[i] = info;
}
return settings;
@@ -337,6 +545,13 @@
};
}
+ /**
+ * set interesting access points to find
+ * @param hotspots access points of interest
+ * @param apLostThreshold number of scans needed to indicate that AP is lost
+ * @param listener object provided to report events on; this object must be unique and must
+ * also be provided on {@link #resetHotlist}
+ */
public void setHotlist(HotspotInfo[] hotspots,
int apLostThreshold, HotlistListener listener) {
validateChannel();
@@ -345,6 +560,10 @@
sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
}
+ /**
+ * remove tracking of interesting access points
+ * @param listener same object provided in {@link #setHotlist}
+ */
public void resetHotlist(HotlistListener listener) {
validateChannel();
sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
@@ -554,6 +773,7 @@
break;
case CMD_OP_FAILED :
((ActionListener) listener).onFailure(msg.arg1, msg.obj);
+ removeListener(msg.arg2);
break;
case CMD_SCAN_RESULT :
((ScanListener) listener).onResults(
@@ -568,11 +788,11 @@
((ParcelableScanResults) msg.obj).getResults());
return;
case CMD_WIFI_CHANGE_DETECTED:
- ((SignificantWifiChangeListener) listener).onChanging(
+ ((WifiChangeListener) listener).onChanging(
((ParcelableScanResults) msg.obj).getResults());
return;
case CMD_WIFI_CHANGES_STABILIZED:
- ((SignificantWifiChangeListener) listener).onQuiescence(
+ ((WifiChangeListener) listener).onQuiescence(
((ParcelableScanResults) msg.obj).getResults());
return;
default:
diff --git a/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java b/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java
deleted file mode 100644
index ac15017..0000000
--- a/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java
+++ /dev/null
@@ -1,48 +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.net.wifi.hotspot;
-
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * TODO: doc
- */
-public class WifiHotspotManager {
-
- private static final String TAG = "WifiHotspotManager";
-
- private Context mContext;
- IWifiHotspotManager mService;
-
- public WifiHotspotManager(Context context, IWifiHotspotManager service) {
- mContext = context;
- mService = service;
- }
-
- public void test() {
- try{
- Log.d(TAG, "test()");
- mService.test();
- }
- catch (RemoteException e) {
- Log.e(TAG, "test() exception");
- e.printStackTrace();
- }
- }
-}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl
similarity index 73%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl
index 2b1601b..e57db64 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
+
+import android.os.Messenger;
/**
- * Interface that allows controlling and querying Hotspot connectivity.
+ * Interface that allows controlling and querying Passpoint connectivity.
*
* {@hide}
*/
-interface IWifiHotspotManager
+interface IPasspointManager
{
- void test();
+ Messenger getMessenger();
+ int getPasspointState();
}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl
index 2b1601b..6f75cbe 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
- void test();
-}
-
+parcelable PasspointCredential;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointCredential.java b/wifi/java/android/net/wifi/passpoint/PasspointCredential.java
new file mode 100644
index 0000000..4218f23
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointCredential.java
@@ -0,0 +1,56 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+public class PasspointCredential implements Parcelable {
+
+ @Override
+ public String toString() {
+ // TODO
+ return null;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // TODO
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<PasspointCredential> CREATOR =
+ new Creator<PasspointCredential>() {
+ @Override
+ public PasspointCredential createFromParcel(Parcel in) {
+ // TODO
+ return null;
+ }
+
+ @Override
+ public PasspointCredential[] newArray(int size) {
+ return new PasspointCredential[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl
index 2b1601b..cc11045 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
- void test();
-}
-
+parcelable PasspointInfo;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointInfo.java b/wifi/java/android/net/wifi/passpoint/PasspointInfo.java
new file mode 100644
index 0000000..d57b0aa
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointInfo.java
@@ -0,0 +1,274 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TODO: doc
+ */
+public class PasspointInfo implements Parcelable {
+
+ /** TODO doc */
+ public static final int ANQP_CAPABILITY = 1 << 0;
+
+ /** TODO doc */
+ public static final int VENUE_NAME = 1 << 1;
+
+ /** TODO doc */
+ public static final int NETWORK_AUTH_TYPE = 1 << 2;
+
+ /** TODO doc */
+ public static final int ROAMING_CONSORTIUM = 1 << 3;
+
+ /** TODO doc */
+ public static final int IP_ADDR_TYPE_AVAILABILITY = 1 << 4;
+
+ /** TODO doc */
+ public static final int NAI_REALM = 1 << 5;
+
+ /** TODO doc */
+ public static final int CELLULAR_NETWORK = 1 << 6;
+
+ /** TODO doc */
+ public static final int DOMAIN_NAME = 1 << 7;
+
+ /** TODO doc */
+ public static final int HOTSPOT_CAPABILITY = 1 << 8;
+
+ /** TODO doc */
+ public static final int OPERATOR_FRIENDLY_NAME = 1 << 9;
+
+ /** TODO doc */
+ public static final int WAN_METRICS = 1 << 10;
+
+ /** TODO doc */
+ public static final int CONNECTION_CAPABILITY = 1 << 11;
+
+ /** TODO doc */
+ public static final int OSU_PROVIDER = 1 << 12;
+
+ /** TODO doc */
+ public static final int PRESET_CRED_MATCH =
+ ANQP_CAPABILITY |
+ HOTSPOT_CAPABILITY |
+ NAI_REALM |
+ CELLULAR_NETWORK |
+ DOMAIN_NAME;
+
+ /** TODO doc */
+ public static final int PRESET_ALL =
+ ANQP_CAPABILITY |
+ VENUE_NAME |
+ NETWORK_AUTH_TYPE |
+ ROAMING_CONSORTIUM |
+ IP_ADDR_TYPE_AVAILABILITY |
+ NAI_REALM |
+ CELLULAR_NETWORK |
+ DOMAIN_NAME |
+ HOTSPOT_CAPABILITY |
+ OPERATOR_FRIENDLY_NAME |
+ WAN_METRICS |
+ CONNECTION_CAPABILITY |
+ OSU_PROVIDER;
+
+
+ /** TODO doc */
+ public String bssid;
+
+ /** TODO doc */
+ public String venueName;
+
+ /** TODO doc */
+ public String networkAuthType;
+
+ /** TODO doc */
+ public String roamingConsortium;
+
+ /** TODO doc */
+ public String ipAddrTypeAvaibility;
+
+ /** TODO doc */
+ public String naiRealm;
+
+ /** TODO doc */
+ public String cellularNetwork;
+
+ /** TODO doc */
+ public String domainName;
+
+ /** TODO doc */
+ public String operatorFriendlyName;
+
+ /** TODO doc */
+ public String wanMetrics;
+
+ /** TODO doc */
+ public String connectionCapability;
+
+ /** TODO doc */
+ public List<PasspointOsuProvider> osuProviderList;
+
+
+ /** default constructor @hide */
+ public PasspointInfo() {
+// osuProviderList = new ArrayList<OsuProvider>();
+ }
+
+ /** copy constructor @hide */
+ public PasspointInfo(PasspointInfo source) {
+ // TODO
+ bssid = source.bssid;
+ venueName = source.venueName;
+ networkAuthType = source.networkAuthType;
+ roamingConsortium = source.roamingConsortium;
+ ipAddrTypeAvaibility = source.ipAddrTypeAvaibility;
+ naiRealm = source.naiRealm;
+ cellularNetwork = source.cellularNetwork;
+ domainName = source.domainName;
+ operatorFriendlyName = source.operatorFriendlyName;
+ wanMetrics = source.wanMetrics;
+ connectionCapability = source.connectionCapability;
+ if (source.osuProviderList != null) {
+ osuProviderList = new ArrayList<PasspointOsuProvider>();
+ for (PasspointOsuProvider osu : source.osuProviderList)
+ osuProviderList.add(new PasspointOsuProvider(osu));
+ }
+ }
+
+ /**
+ * Convert mask to ANQP subtypes, for supplicant command use.
+ *
+ * @param mask The ANQP subtypes mask.
+ * @return String of ANQP subtypes, good for supplicant command use
+ * @hide
+ */
+ public static String toAnqpSubtypes(int mask) {
+ StringBuilder sb = new StringBuilder();
+ if ((mask & ANQP_CAPABILITY) != 0) sb.append("257,");
+ if ((mask & VENUE_NAME) != 0) sb.append("258,");
+ if ((mask & NETWORK_AUTH_TYPE) != 0) sb.append("260,");
+ if ((mask & ROAMING_CONSORTIUM) != 0) sb.append("261,");
+ if ((mask & IP_ADDR_TYPE_AVAILABILITY) != 0) sb.append("262,");
+ if ((mask & NAI_REALM) != 0) sb.append("263,");
+ if ((mask & CELLULAR_NETWORK) != 0) sb.append("264,");
+ if ((mask & DOMAIN_NAME) != 0) sb.append("268,");
+ if ((mask & HOTSPOT_CAPABILITY) != 0) sb.append("hs20:2,");
+ if ((mask & OPERATOR_FRIENDLY_NAME) != 0) sb.append("hs20:3,");
+ if ((mask & WAN_METRICS) != 0) sb.append("hs20:4,");
+ if ((mask & CONNECTION_CAPABILITY) != 0) sb.append("hs20:5,");
+ if ((mask & OSU_PROVIDER) != 0) sb.append("hs20:8,");
+ if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1);
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("BSSID: ").append(bssid);
+ if (venueName != null)
+ sb.append(" venueName: ").append(venueName);
+ if (networkAuthType != null)
+ sb.append(" networkAuthType: ").append(networkAuthType);
+ if (roamingConsortium != null)
+ sb.append(" roamingConsortium: ").append(roamingConsortium);
+ if (ipAddrTypeAvaibility != null)
+ sb.append(" ipAddrTypeAvaibility: ").append(ipAddrTypeAvaibility);
+ if (naiRealm != null)
+ sb.append(" naiRealm: ").append(naiRealm);
+ if (cellularNetwork != null)
+ sb.append(" cellularNetwork: ").append(cellularNetwork);
+ if (domainName != null)
+ sb.append(" domainName: ").append(domainName);
+ if (operatorFriendlyName != null)
+ sb.append(" operatorFriendlyName: ").append(operatorFriendlyName);
+ if (wanMetrics != null)
+ sb.append(" wanMetrics: ").append(wanMetrics);
+ if (connectionCapability != null)
+ sb.append(" connectionCapability: ").append(connectionCapability);
+ if (osuProviderList != null)
+ sb.append(" osuProviderList: (size=" + osuProviderList.size() + ")");
+ return sb.toString();
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeValue(bssid);
+ out.writeValue(venueName);
+ out.writeValue(networkAuthType);
+ out.writeValue(roamingConsortium);
+ out.writeValue(ipAddrTypeAvaibility);
+ out.writeValue(naiRealm);
+ out.writeValue(cellularNetwork);
+ out.writeValue(domainName);
+ out.writeValue(operatorFriendlyName);
+ out.writeValue(wanMetrics);
+ out.writeValue(connectionCapability);
+ if (osuProviderList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(osuProviderList.size());
+ for (PasspointOsuProvider osu : osuProviderList)
+ osu.writeToParcel(out, flags);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Parcelable.Creator<PasspointInfo> CREATOR =
+ new Parcelable.Creator<PasspointInfo>() {
+ @Override
+ public PasspointInfo createFromParcel(Parcel in) {
+ PasspointInfo p = new PasspointInfo();
+ p.bssid = (String) in.readValue(String.class.getClassLoader());
+ p.venueName = (String) in.readValue(String.class.getClassLoader());
+ p.networkAuthType = (String) in.readValue(String.class.getClassLoader());
+ p.roamingConsortium = (String) in.readValue(String.class.getClassLoader());
+ p.ipAddrTypeAvaibility = (String) in.readValue(String.class.getClassLoader());
+ p.naiRealm = (String) in.readValue(String.class.getClassLoader());
+ p.cellularNetwork = (String) in.readValue(String.class.getClassLoader());
+ p.domainName = (String) in.readValue(String.class.getClassLoader());
+ p.operatorFriendlyName = (String) in.readValue(String.class.getClassLoader());
+ p.wanMetrics = (String) in.readValue(String.class.getClassLoader());
+ p.connectionCapability = (String) in.readValue(String.class.getClassLoader());
+ int n = in.readInt();
+ if (n > 0) {
+ p.osuProviderList = new ArrayList<PasspointOsuProvider>();
+ for (int i = 0; i < n; i++) {
+ PasspointOsuProvider osu = PasspointOsuProvider.CREATOR.createFromParcel(in);
+ p.osuProviderList.add(osu);
+ }
+ }
+ return p;
+ }
+
+ @Override
+ public PasspointInfo[] newArray(int size) {
+ return new PasspointInfo[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointManager.java b/wifi/java/android/net/wifi/passpoint/PasspointManager.java
new file mode 100644
index 0000000..234a44c
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointManager.java
@@ -0,0 +1,504 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * TODO: doc
+ */
+public class PasspointManager {
+
+ private static final String TAG = "PasspointManager";
+
+ private static final boolean DBG = true;
+
+ /* Passpoint states values */
+
+ /** Passpoint is in an known state. This should only occur in boot time */
+ public static final int PASSPOINT_STATE_UNKNOWN = 0;
+
+ /** Passpoint is disabled. This occurs when wifi is disabled. */
+ public static final int PASSPOINT_STATE_DISABLED = 1;
+
+ /** Passpoint is enabled and in discovery state. */
+ public static final int PASSPOINT_STATE_DISCOVERY = 2;
+
+ /** Passpoint is enabled and in access state. */
+ public static final int PASSPOINT_STATE_ACCESS = 3;
+
+ /** Passpoint is enabled and in provisioning state. */
+ public static final int PASSPOINT_STATE_PROVISION = 4;
+
+ /* Passpoint callback error codes */
+
+ /** Indicates that the operation failed due to an internal error */
+ public static final int ERROR = 0;
+
+ /** Indicates that the operation failed because wifi is disabled */
+ public static final int WIFI_DISABLED = 1;
+
+ /** Indicates that the operation failed because the framework is busy */
+ public static final int BUSY = 2;
+
+ /* Passpoint broadcasts */
+
+ /**
+ * Broadcast intent action indicating that the state of Passpoint
+ * connectivity has changed
+ */
+ public static final String PASSPOINT_STATE_CHANGED_ACTION =
+ "android.net.wifi.passpoint.STATE_CHANGE";
+
+ /**
+ * Broadcast intent action indicating that the saved Passpoint credential
+ * list has changed
+ */
+ public static final String PASSPOINT_CRED_CHANGED_ACTION =
+ "android.net.wifi.passpoint.CRED_CHANGE";
+
+ /**
+ * Broadcast intent action indicating that Passpoint online sign up is
+ * avaiable.
+ * @hide
+ */
+ public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
+ "android.net.wifi.passpoint.OSU_AVAILABLE";
+
+ /**
+ * Broadcast intent action indicating that user remediation is required
+ * @hide
+ */
+ public static final String PASSPOINT_USER_REM_REQ_ACTION =
+ "android.net.wifi.passpoint.USER_REM_REQ";
+
+
+ /**
+ * Interface for callback invocation when framework channel is lost
+ */
+ public interface ChannelListener {
+ /**
+ * The channel to the framework has been disconnected. Application could
+ * try re-initializing using {@link #initialize}
+ */
+ public void onChannelDisconnected();
+ }
+
+ /**
+ * Interface for callback invocation on an application action
+ */
+ public interface ActionListener {
+ /** The operation succeeded */
+ public void onSuccess();
+
+ /**
+ * * The operation failed
+ *
+ * @param reason The reason for failure could be one of
+ * {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
+ */
+ public void onFailure(int reason);
+ }
+
+ /**
+ * Interface for callback invocation when doing OSU or user remediation
+ * @hide
+ */
+ public interface OsuRemListener {
+ /** The operation succeeded */
+ public void onSuccess();
+
+ /**
+ * The operation failed
+ *
+ * @param reason The reason for failure could be one of
+ * {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
+ */
+ public void onFailure(int reason);
+
+ /**
+ * Browser launch is requried for user interaction. When this callback
+ * is called, app should launch browser / webview to the given URL.
+ *
+ * @param url URL for browser launch
+ */
+ public void onBrowserLaunch(String url);
+
+ /**
+ * When this is called, app should dismiss the previously lanched browser.
+ */
+ public void onBrowserDismiss();
+ }
+
+ /**
+ * A channel that connects the application to the wifi passpoint framework.
+ * Most passpoint operations require a Channel as an argument.
+ * An instance of Channel is obtained by doing a call on {@link #initialize}
+ */
+ public static class Channel {
+ private final static int INVALID_LISTENER_KEY = 0;
+
+ private ChannelListener mChannelListener;
+
+ private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
+ private HashMap<Integer, Integer> mListenerMapCount = new HashMap<Integer, Integer>();
+ private Object mListenerMapLock = new Object();
+ private int mListenerKey = 0;
+
+ private List<ScanResult> mAnqpRequest = new LinkedList<ScanResult>();
+ private Object mAnqpRequestLock = new Object();
+
+ private AsyncChannel mAsyncChannel;
+ private PasspointHandler mHandler;
+ Context mContext;
+
+ Channel(Context context, Looper looper, ChannelListener l) {
+ mAsyncChannel = new AsyncChannel();
+ mHandler = new PasspointHandler(looper);
+ mChannelListener = l;
+ mContext = context;
+ }
+
+ private int putListener(Object listener) {
+ return putListener(listener, 1);
+ }
+
+ private int putListener(Object listener, int count) {
+ if (listener == null || count <= 0) return INVALID_LISTENER_KEY;
+ int key;
+ synchronized (mListenerMapLock) {
+ do {
+ key = mListenerKey++;
+ } while (key == INVALID_LISTENER_KEY);
+ mListenerMap.put(key, listener);
+ mListenerMapCount.put(key, count);
+ }
+ return key;
+ }
+
+ private Object getListener(int key, boolean force) {
+ Log.d(TAG, "getListener() key=" + key + " force=" + force);
+ if (key == INVALID_LISTENER_KEY) return null;
+ synchronized (mListenerMapLock) {
+ if (!force) {
+ int count = mListenerMapCount.get(key);
+ Log.d(TAG, "count=" + count);
+ mListenerMapCount.put(key, --count);
+ if (count > 0) return null;
+ }
+ Log.d(TAG, "remove key");
+ mListenerMapCount.remove(key);
+ return mListenerMap.remove(key);
+ }
+ }
+
+ private void anqpRequestStart(ScanResult sr) {
+ Log.d(TAG, "anqpRequestStart sr.bssid=" + sr.BSSID);
+ synchronized(mAnqpRequestLock) { mAnqpRequest.add(sr); }
+ }
+
+ private void anqpRequestFinish(PasspointInfo result) {
+ Log.d(TAG, "anqpRequestFinish pi.bssid=" + result.bssid);
+ synchronized(mAnqpRequestLock) {
+ for (ScanResult sr : mAnqpRequest)
+ if (sr.BSSID.equals(result.bssid)) {
+ Log.d(TAG, "find hit " + result.bssid);
+ sr.passpoint = result;
+ mAnqpRequest.remove(sr);
+ Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
+ break;
+ }
+ }
+ }
+
+ private void anqpRequestFinish(ScanResult sr) {
+ Log.d(TAG, "anqpRequestFinish sr.bssid=" + sr.BSSID);
+ synchronized(mAnqpRequestLock) {
+ for (ScanResult sr1 : mAnqpRequest)
+ if (sr1.BSSID.equals(sr.BSSID)) {
+ mAnqpRequest.remove(sr1);
+ break;
+ }
+ }
+ }
+
+ class PasspointHandler extends Handler {
+ PasspointHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ Object listener = getListener(message.arg2, false);
+ switch (message.what) {
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ if (mChannelListener != null) {
+ mChannelListener.onChannelDisconnected();
+ mChannelListener = null;
+ }
+ break;
+
+ case REQUEST_ANQP_INFO_SUCCEEDED:
+ PasspointInfo result = (PasspointInfo) message.obj;
+ anqpRequestFinish(result);
+ if (listener != null) {
+ ((ActionListener) listener).onSuccess();
+ }
+ break;
+
+ case REQUEST_ANQP_INFO_FAILED:
+ anqpRequestFinish((ScanResult) message.obj);
+ if (listener == null) getListener(message.arg2, true);
+ if (listener != null) {
+ ((ActionListener) listener).onFailure(message.arg1);
+ }
+ break;
+
+ default:
+ Log.d(TAG, "Ignored " + message);
+ break;
+ }
+ }
+ }
+
+ }
+
+
+ private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
+
+ /** @hide */
+ public static final int REQUEST_ANQP_INFO = BASE + 1;
+
+ /** @hide */
+ public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
+
+ /** @hide */
+ public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
+
+ /** @hide */
+ public static final int REQUEST_OSU_INFO = BASE + 4;
+
+ /** @hide */
+ public static final int REQUEST_OSU_INFO_FAILED = BASE + 5;
+
+ /** @hide */
+ public static final int REQUEST_OSU_INFO_SUCCEEDED = BASE + 6;
+
+
+ private Context mContext;
+ IPasspointManager mService;
+
+
+ /**
+ * TODO: doc
+ * @param context
+ * @param service
+ */
+ public PasspointManager(Context context, IPasspointManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Registers the application with the framework. This function must be the
+ * first to be called before any async passpoint operations are performed.
+ *
+ * @param srcContext is the context of the source
+ * @param srcLooper is the Looper on which the callbacks are receivied
+ * @param listener for callback at loss of framework communication. Can be
+ * null.
+ * @return Channel instance that is necessary for performing any further
+ * passpoint operations
+ */
+ public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
+ Messenger messenger = getMessenger();
+ if (messenger == null) return null;
+
+ Channel c = new Channel(srcContext, srcLooper, listener);
+ if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
+ == AsyncChannel.STATUS_SUCCESSFUL) {
+ return c;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * STOPSHIP: temp solution, should use supplicant manager instead, check
+ * with b/13931972
+ *
+ * @hide
+ */
+ public Messenger getMessenger() {
+ try {
+ return mService.getMessenger();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get Passpoint state.
+ *
+ * @return One of {@link #PASSPOINT_STATE_DISABLED},
+ * {@link #PASSPOINT_STATE_DISCOVERY},
+ * {@link #PASSPOINT_STATE_ACCESS},
+ * {@link #PASSPOINT_STATE_PROVISION},
+ * {@link #PASSPOINT_STATE_UNKNOWN}
+ */
+ public int getPasspointState() {
+ try{
+ return mService.getPasspointState();
+ }
+ catch (RemoteException e) {
+ return PASSPOINT_STATE_UNKNOWN;
+ }
+ }
+
+ /**
+ * TODO: doc
+ *
+ * @param c
+ * @param requested
+ * @param mask
+ * @param listener
+ *
+ * @hide
+ */
+ public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
+ ActionListener listener) {
+ Log.d(TAG, "requestAnqpInfo start");
+ Log.d(TAG, "requested.size=" + requested.size());
+ checkChannel(c);
+ List<ScanResult> list = new ArrayList<ScanResult>();
+ for (ScanResult sr : requested) if (sr.capabilities.contains("[HS20]")) {
+ list.add(sr);
+ c.anqpRequestStart(sr);
+ Log.d(TAG, "adding " + sr.BSSID);
+ }
+ int count = list.size();
+ Log.d(TAG, "after filter, count=" + count);
+ if (count == 0) {
+ if (DBG) Log.d(TAG, "ANQP info request contains no HS20 APs, skipped");
+ listener.onSuccess();
+ return;
+ }
+ int key = c.putListener(listener, count);
+ for (ScanResult sr : list)
+ c.mAsyncChannel.sendMessage(REQUEST_ANQP_INFO, mask, key, sr);
+ Log.d(TAG, "requestAnqpInfo end");
+ }
+
+ /**
+ * TODO: doc
+ *
+ * @param c
+ * @param requested
+ * @param resolution
+ * @param listener
+ */
+ public void requestOsuIcons(Channel c, List<PasspointOsuProvider> requested,
+ int resolution, ActionListener listener) {
+ }
+
+ /**
+ * TODO: doc
+ *
+ * @param requested
+ * @return
+ */
+ public List<PasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
+ return null;
+ }
+
+ /* TODO: add credential APIs */
+
+ /**
+ * Give a list of all saved Passpoint credentials.
+ *
+ * @return The list of credentials
+ */
+ public List<PasspointCredential> getSavedCredentials() {
+ return null;
+ }
+
+ /**
+ * Add a new Passpoint credential.
+ *
+ * @param cred The credential to be added
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ public boolean addCredential(PasspointCredential cred) {
+ return true;
+ }
+
+ /**
+ * Update an existing Passpoint credential.
+ *
+ * @param cred The credential to be updated
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ public boolean updateCredential(PasspointCredential cred) {
+ return true;
+ }
+
+ /**
+ * Remove an existing Passpoint credential.
+ *
+ * @param cred The credential to be removed
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ public boolean removeCredential(PasspointCredential cred) {
+ return true;
+ }
+
+ /** @hide */
+ public void startOsu(Channel c, PasspointOsuProvider selected, OsuRemListener listener) {
+
+ }
+
+ /** @hide */
+ public void startUserRemediation(Channel c, OsuRemListener listener) {
+ }
+
+ /**
+ * Select and connect to a Passpoint network.
+ *
+ * @param selected Selected Passpoint network, see {@link PasspointPolicy}
+ */
+ public void connect(PasspointPolicy selected) {
+ }
+
+ private static void checkChannel(Channel c) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ }
+}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl
similarity index 77%
rename from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
rename to wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl
index 2b1601b..f5ecb7c 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
- void test();
-}
-
+parcelable PasspointOsuProvider;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java
new file mode 100644
index 0000000..80d5315
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java
@@ -0,0 +1,145 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO: doc
+ */
+public class PasspointOsuProvider implements Parcelable {
+
+ /** TODO: doc */
+ public static final int OSU_METHOD_UNKNOWN = -1;
+
+ /** TODO: doc */
+ public static final int OSU_METHOD_OMADM = 0;
+
+ /** TODO: doc */
+ public static final int OSU_METHOD_SOAP = 1;
+
+ /** TODO: doc */
+ public String ssid;
+
+ /** TODO: doc */
+ public String friendlyName;
+
+ /** TODO: doc */
+ public String serverUri;
+
+ /** TODO: doc */
+ public int osuMethod = OSU_METHOD_UNKNOWN;
+
+ /** TODO: doc */
+ public int iconWidth;
+
+ /** TODO: doc */
+ public int iconHeight;
+
+ /** TODO: doc */
+ public String iconType;
+
+ /** TODO: doc */
+ public String iconFileName;
+
+ /** TODO: doc */
+ public Object icon; // TODO: should change to image format
+
+ /** TODO: doc */
+ public String osuNai;
+
+ /** TODO: doc */
+ public String osuService;
+
+
+ /** default constructor @hide */
+ public PasspointOsuProvider() {
+ // TODO
+ }
+
+ /** copy constructor @hide */
+ public PasspointOsuProvider(PasspointOsuProvider source) {
+ // TODO
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("SSID: ").append(ssid);
+ if (friendlyName != null)
+ sb.append(" friendlyName: ").append(friendlyName);
+ if (serverUri != null)
+ sb.append(" serverUri: ").append(serverUri);
+ sb.append(" osuMethod: ").append(osuMethod);
+ if (iconFileName != null) {
+ sb.append(" icon: [").append(iconWidth).append("x")
+ .append(iconHeight).append(" ")
+ .append(iconType).append(" ")
+ .append(iconFileName);
+ }
+ if (osuNai != null)
+ sb.append(" osuNai: ").append(osuNai);
+ if (osuService != null)
+ sb.append(" osuService: ").append(osuService);
+ return sb.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeValue(ssid);
+ out.writeValue(friendlyName);
+ out.writeValue(serverUri);
+ out.writeInt(osuMethod);
+ out.writeInt(iconWidth);
+ out.writeInt(iconHeight);
+ out.writeValue(iconType);
+ out.writeValue(iconFileName);
+ out.writeValue(osuNai);
+ out.writeValue(osuService);
+ // TODO: icon image?
+ }
+
+ public static final Parcelable.Creator<PasspointOsuProvider> CREATOR =
+ new Parcelable.Creator<PasspointOsuProvider>() {
+ @Override
+ public PasspointOsuProvider createFromParcel(Parcel in) {
+ PasspointOsuProvider osu = new PasspointOsuProvider();
+ osu.ssid = (String) in.readValue(String.class.getClassLoader());
+ osu.friendlyName = (String) in.readValue(String.class.getClassLoader());
+ osu.serverUri = (String) in.readValue(String.class.getClassLoader());
+ osu.osuMethod = in.readInt();
+ osu.iconWidth = in.readInt();
+ osu.iconHeight = in.readInt();
+ osu.iconType = (String) in.readValue(String.class.getClassLoader());
+ osu.iconFileName = (String) in.readValue(String.class.getClassLoader());
+ osu.osuNai = (String) in.readValue(String.class.getClassLoader());
+ osu.osuService = (String) in.readValue(String.class.getClassLoader());
+ return osu;
+ }
+
+ @Override
+ public PasspointOsuProvider[] newArray(int size) {
+ return new PasspointOsuProvider[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl
index 2b1601b..c2cc731 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
- void test();
-}
-
+parcelable PasspointPolicy;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java
new file mode 100644
index 0000000..3a8806b
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java
@@ -0,0 +1,55 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+public class PasspointPolicy implements Parcelable {
+
+ @Override
+ public String toString() {
+ // TODO
+ return null;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // TODO
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<PasspointPolicy> CREATOR =
+ new Creator<PasspointPolicy>() {
+ @Override
+ public PasspointPolicy createFromParcel(Parcel in) {
+ return null;
+ }
+
+ @Override
+ public PasspointPolicy[] newArray(int size) {
+ return new PasspointPolicy[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/WifiTree.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/WifiTree.aidl
index 2b1601b..8e2fab742 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/WifiTree.aidl
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
- void test();
-}
-
+parcelable WifiTree;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiTree.java b/wifi/java/android/net/wifi/passpoint/WifiTree.java
new file mode 100644
index 0000000..8fdb6e1
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiTree.java
@@ -0,0 +1,51 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/** @hide */
+public class WifiTree implements Parcelable {
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ // TODO
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Parcelable.Creator<WifiTree> CREATOR =
+ new Parcelable.Creator<WifiTree>() {
+ @Override
+ public WifiTree createFromParcel(Parcel in) {
+ // TODO
+ return null;
+ }
+
+ @Override
+ public WifiTree[] newArray(int size) {
+ return new WifiTree[size];
+ }
+ };
+}