Merge "Publish new Telecomm API for Connection Services"
diff --git a/Android.mk b/Android.mk
index 89b2884..19ee855 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 \
@@ -333,7 +335,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 460076e..1fd5d63 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29,9 +29,8 @@
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_SERVICE = "android.permission.BIND_TRUST_AGENT_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 +1016,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 +3236,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 +3247,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 +3348,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 +3478,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 +3485,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 +3554,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 +4510,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 +4518,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 +4546,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 +4907,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 +5217,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 +6630,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 +6661,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 +7105,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 +12280,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 +12309,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 +12318,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 +12329,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 +12344,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 +12371,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 {
@@ -12476,16 +12446,17 @@
field public static final int MESSAGE_FEATURE_ABORT = 0; // 0x0
field public static final int MESSAGE_GET_CEC_VERSION = 159; // 0x9f
field public static final int MESSAGE_GET_MENU_LANGUAGE = 145; // 0x91
- field public static final int MESSAGE_GET_OSD_NAME = 70; // 0x46
field public static final int MESSAGE_GIVE_AUDIO_STATUS = 113; // 0x71
field public static final int MESSAGE_GIVE_DECK_STATUS = 26; // 0x1a
field public static final int MESSAGE_GIVE_DEVICE_POWER_STATUS = 143; // 0x8f
field public static final int MESSAGE_GIVE_DEVICE_VENDOR_ID = 140; // 0x8c
+ field public static final int MESSAGE_GIVE_OSD_NAME = 70; // 0x46
field public static final int MESSAGE_GIVE_PHYSICAL_ADDRESS = 131; // 0x83
field public static final int MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 125; // 0x7d
field public static final int MESSAGE_GIVE_TUNER_DEVICE_STATUS = 8; // 0x8
field public static final int MESSAGE_IMAGE_VIEW_ON = 4; // 0x4
field public static final int MESSAGE_INACTIVE_SOURCE = 157; // 0x9d
+ field public static final int MESSAGE_INITIATE_ARC = 192; // 0xc0
field public static final int MESSAGE_MENU_REQUEST = 141; // 0x8d
field public static final int MESSAGE_MENU_STATUS = 142; // 0x8e
field public static final int MESSAGE_PLAY = 65; // 0x41
@@ -12493,10 +12464,14 @@
field public static final int MESSAGE_RECORD_ON = 9; // 0x9
field public static final int MESSAGE_RECORD_STATUS = 10; // 0xa
field public static final int MESSAGE_RECORD_TV_SCREEN = 15; // 0xf
+ field public static final int MESSAGE_REPORT_ARC_INITIATED = 193; // 0xc1
+ field public static final int MESSAGE_REPORT_ARC_TERMINATED = 194; // 0xc2
field public static final int MESSAGE_REPORT_AUDIO_STATUS = 122; // 0x7a
field public static final int MESSAGE_REPORT_PHYSICAL_ADDRESS = 132; // 0x84
field public static final int MESSAGE_REPORT_POWER_STATUS = 144; // 0x90
field public static final int MESSAGE_REQUEST_ACTIVE_SOURCE = 133; // 0x85
+ field public static final int MESSAGE_REQUEST_ARC_INITIATION = 195; // 0xc3
+ field public static final int MESSAGE_REQUEST_ARC_TERMINATION = 196; // 0xc4
field public static final int MESSAGE_ROUTING_CHANGE = 128; // 0x80
field public static final int MESSAGE_ROUTING_INFORMATION = 129; // 0x81
field public static final int MESSAGE_SELECT_ANALOG_SERVICE = 146; // 0x92
@@ -12514,6 +12489,7 @@
field public static final int MESSAGE_STANDBY = 54; // 0x36
field public static final int MESSAGE_SYSTEM_AUDIO_MODE_REQUEST = 112; // 0x70
field public static final int MESSAGE_SYSTEM_AUDIO_MODE_STATUS = 126; // 0x7e
+ field public static final int MESSAGE_TERMINATE_ARC = 197; // 0xc5
field public static final int MESSAGE_TEXT_VIEW_ON = 13; // 0xd
field public static final int MESSAGE_TIMER_CLEARED_STATUS = 67; // 0x43
field public static final int MESSAGE_TIMER_STATUS = 53; // 0x35
@@ -12528,9 +12504,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
}
@@ -12576,6 +12558,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 {
@@ -13732,16 +13735,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 {
@@ -15871,6 +15875,16 @@
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 LocalServerSocket {
ctor public LocalServerSocket(java.lang.String) throws java.io.IOException;
ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -16012,6 +16026,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);
+ 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 hasGateway();
+ method public boolean isDefaultRoute();
+ method public boolean isHostRoute();
+ 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;
@@ -16848,6 +16876,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);
@@ -16865,19 +16973,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 {
@@ -17073,6 +17168,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 {
@@ -19578,6 +19781,7 @@
public class BatteryProperty implements android.os.Parcelable {
method public int describeContents();
method public int getInt();
+ method public long getLong();
method public void readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPACITY = 4; // 0x4
@@ -19585,6 +19789,7 @@
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int CURRENT_AVERAGE = 3; // 0x3
field public static final int CURRENT_NOW = 2; // 0x2
+ field public static final int ENERGY_COUNTER = 4; // 0x4
}
public class Binder implements android.os.IBinder {
@@ -25319,82 +25524,16 @@
public class TrustAgentService extends android.app.Service {
ctor public TrustAgentService();
- method protected final void enableTrust(java.lang.String, long, boolean);
+ method public final void grantTrust(java.lang.CharSequence, long, boolean);
method public final android.os.IBinder onBind(android.content.Intent);
- method protected void onUnlockAttempt(boolean);
- method protected final void revokeTrust();
+ method public void onUnlockAttempt(boolean);
+ method public final void revokeTrust();
field public static final java.lang.String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
field public static final java.lang.String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
}
}
-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 {
@@ -27195,6 +27334,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
@@ -30067,6 +30207,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();
@@ -30905,6 +31051,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/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..ca6b008 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -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() {
@@ -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..f7f51fe 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
@@ -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 7213c78..a71a74d 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -120,7 +120,7 @@
public static final int MESSAGE_TIMER_CLEARED_STATUS = 0x043;
public static final int MESSAGE_USER_CONTROL_PRESSED = 0x44;
public static final int MESSAGE_USER_CONTROL_RELEASED = 0x45;
- public static final int MESSAGE_GET_OSD_NAME = 0x46;
+ public static final int MESSAGE_GIVE_OSD_NAME = 0x46;
public static final int MESSAGE_SET_OSD_NAME = 0x47;
public static final int MESSAGE_SET_OSD_STRING = 0x64;
public static final int MESSAGE_SET_TIMER_PROGRAM_TITLE = 0x67;
@@ -158,6 +158,12 @@
public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 0xA0;
public static final int MESSAGE_CLEAR_EXTERNAL_TIMER = 0xA1;
public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
+ public static final int MESSAGE_INITIATE_ARC = 0xC0;
+ public static final int MESSAGE_REPORT_ARC_INITIATED = 0xC1;
+ public static final int MESSAGE_REPORT_ARC_TERMINATED = 0xC2;
+ public static final int MESSAGE_REQUEST_ARC_INITIATION = 0xC3;
+ public static final int MESSAGE_REQUEST_ARC_TERMINATION = 0xC4;
+ public static final int MESSAGE_TERMINATE_ARC = 0xC5;
public static final int MESSAGE_ABORT = 0xFF;
public static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
@@ -165,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/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/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/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 1d051dd..e566549 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -28,19 +28,18 @@
/**
* A simple container for route information.
+ * <p>
+ * This is used both to describe static network configuration and live network
+ * configuration information. In the static case the interface name (retrieved
+ * via {@link #getInterface}) should be {@code null} as that information will not
+ * yet be known.
*
- * 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 may be configured with:
+ * <ul>
+ * <li>a destination {@link LinkAddress} for directly-connected subnets,
+ * <li>a gateway {@link InetAddress} for default routes,
+ * <li>or both for a subnet.
+ * </ul>
*/
public class RouteInfo implements Parcelable {
/**
@@ -67,7 +66,7 @@
*
* 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}.
*
@@ -76,6 +75,8 @@
* @param destination the destination prefix
* @param gateway the IP address to route packets through
* @param iface the interface name to send packets on
+ *
+ * @hide
*/
public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
if (destination == null) {
@@ -108,22 +109,51 @@
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);
}
+ /**
+ * Constructs a {@code RouteInfo} object representing a direct connected subnet.
+ *
+ * @param host the {@link LinkAddress} describing the address and prefix length of the subnet.
+ */
public RouteInfo(LinkAddress host) {
this(host, 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 +183,102 @@
return val;
}
-
+ /**
+ * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}.
+ *
+ * @return {@link LinkAddress} specifying the destination.
+ */
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.
+ */
public InetAddress getGateway() {
return mGateway;
}
+ /**
+ * Retrieves the interface used for this route, if known. Note that for static
+ * network configurations, this won't be set.
+ *
+ * @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 is null or 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.
+ */
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
+ */
public boolean hasGateway() {
return mHasGateway;
}
+ /**
+ * @hide
+ */
+ 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
+ *
+ * @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,30 +286,6 @@
return val;
}
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- if (mDestination == null) {
- dest.writeByte((byte) 0);
- } else {
- dest.writeByte((byte) 1);
- dest.writeByteArray(mDestination.getAddress().getAddress());
- dest.writeInt(mDestination.getNetworkPrefixLength());
- }
-
- if (mGateway == null) {
- dest.writeByte((byte) 0);
- } else {
- dest.writeByte((byte) 1);
- dest.writeByteArray(mGateway.getAddress());
- }
-
- dest.writeString(mInterface);
- }
-
- @Override
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -229,17 +306,51 @@
: mInterface.equals(target.getInterface());
return sameDestination && sameAddress && sameInterface
- && mIsDefault == target.mIsDefault;
+ && 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);
+ + (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);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mDestination.getAddress().getAddress());
+ dest.writeInt(mDestination.getNetworkPrefixLength());
+ }
+
+ if (mGateway == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mGateway.getAddress());
+ }
+
+ dest.writeString(mInterface);
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
public static final Creator<RouteInfo> CREATOR =
new Creator<RouteInfo>() {
public RouteInfo createFromParcel(Parcel in) {
@@ -279,39 +390,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/BatteryManager.java b/core/java/android/os/BatteryManager.java
index f339e52..32050dc 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -146,9 +146,9 @@
return null;
}
- BatteryProperty prop = new BatteryProperty(Integer.MIN_VALUE);
+ BatteryProperty prop = new BatteryProperty();
if ((mBatteryPropertiesRegistrar.getProperty(id, prop) == 0) &&
- (prop.getInt() != Integer.MIN_VALUE))
+ (prop.getLong() != Long.MIN_VALUE))
return prop;
else
return null;
diff --git a/core/java/android/os/BatteryProperty.java b/core/java/android/os/BatteryProperty.java
index ec73952..0ed856e 100644
--- a/core/java/android/os/BatteryProperty.java
+++ b/core/java/android/os/BatteryProperty.java
@@ -53,20 +53,18 @@
*/
public static final int CAPACITY = 4;
- private int mValueInt;
-
/**
- * @hide
+ * Battery remaining energy in nanowatt-hours, as a long integer.
*/
- public BatteryProperty(int value) {
- mValueInt = value;
- }
+ public static final int ENERGY_COUNTER = 4;
+
+ private long mValueLong;
/**
* @hide
*/
public BatteryProperty() {
- mValueInt = Integer.MIN_VALUE;
+ mValueLong = Long.MIN_VALUE;
}
/**
@@ -79,9 +77,21 @@
* @return The queried property value, or Integer.MIN_VALUE if not supported.
*/
public int getInt() {
- return mValueInt;
+ return (int)mValueLong;
}
+ /**
+ * Return the value of a property of long type previously queried
+ * via {@link BatteryManager#getProperty
+ * BatteryManager.getProperty()}. If the platform does
+ * not provide the property queried, this value will be
+ * Long.MIN_VALUE.
+ *
+ * @return The queried property value, or Long.MIN_VALUE if not supported.
+ */
+ public long getLong() {
+ return mValueLong;
+ }
/*
* Parcel read/write code must be kept in sync with
* frameworks/native/services/batteryservice/BatteryProperty.cpp
@@ -92,11 +102,11 @@
}
public void readFromParcel(Parcel p) {
- mValueInt = p.readInt();
+ mValueLong = p.readLong();
}
public void writeToParcel(Parcel p, int flags) {
- p.writeInt(mValueInt);
+ p.writeLong(mValueLong);
}
public static final Parcelable.Creator<BatteryProperty> CREATOR
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 89f4388..e896063 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -769,6 +769,28 @@
public static final String
ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
+ /**
+ * Activity Action: Show Device Name 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 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
/**
@@ -2889,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 */
@@ -4533,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
@@ -5319,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/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index c346771..9e4c2bf 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -23,6 +23,6 @@
* @hide
*/
oneway interface ITrustAgentServiceCallback {
- void enableTrust(String message, long durationMs, boolean initiatedByUser);
+ void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser);
void revokeTrust();
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index d5ce429..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;
/**
@@ -29,12 +34,12 @@
* to be trusted.
*
* <p>To extend this class, you must declare the service in your manifest file with
- * the {@link android.Manifest.permission#BIND_TRUST_AGENT_SERVICE} permission
+ * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
* and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
* <pre>
* <service android:name=".TrustAgent"
* android:label="@string/service_name"
- * android:permission="android.permission.BIND_TRUST_AGENT_SERVICE">
+ * android:permission="android.permission.BIND_TRUST_AGENT">
* <intent-filter>
* <action android:name="android.service.trust.TrustAgentService" />
* </intent-filter>
@@ -47,7 +52,7 @@
* {@link android.R.styleable#TrustAgent}. For example:</p>
*
* <pre>
- * <trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+ * <trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
* android:settingsActivity=".TrustAgentSettings" /></pre>
*/
public class TrustAgentService extends Service {
@@ -83,12 +88,28 @@
};
};
+ @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.
*
* @param successful true if the attempt succeeded
*/
- protected void onUnlockAttempt(boolean successful) {
+ public void onUnlockAttempt(boolean successful) {
}
private void onError(String msg) {
@@ -96,7 +117,7 @@
}
/**
- * Call to enable trust on the device.
+ * Call to grant trust on the device.
*
* @param message describes why the device is trusted, e.g. "Trusted by location".
* @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
@@ -104,10 +125,10 @@
* @param initiatedByUser indicates that the user has explicitly initiated an action that proves
* the user is about to use the device.
*/
- protected final void enableTrust(String message, long durationMs, boolean initiatedByUser) {
+ public final void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser) {
if (mCallback != null) {
try {
- mCallback.enableTrust(message, durationMs, initiatedByUser);
+ mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
} catch (RemoteException e) {
onError("calling enableTrust()");
}
@@ -117,7 +138,7 @@
/**
* Call to revoke trust on the device.
*/
- protected final void revokeTrust() {
+ public final void revokeTrust() {
if (mCallback != null) {
try {
mCallback.revokeTrust();
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/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/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/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index f23c64f..2b62552 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -30,6 +30,7 @@
import android.media.Metadata;
import android.media.SubtitleController;
import android.media.SubtitleTrack.RenderingWidget;
+import android.media.TtmlRenderer;
import android.media.WebVttRenderer;
import android.net.Uri;
import android.os.Looper;
@@ -314,6 +315,7 @@
final SubtitleController controller = new SubtitleController(
context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
controller.registerRenderer(new WebVttRenderer(context));
+ controller.registerRenderer(new TtmlRenderer(context));
mMediaPlayer.setSubtitleAnchor(controller, this);
if (mAudioSession != 0) {
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/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 cdb77f1..f262a93 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"
@@ -2613,7 +2613,7 @@
<!-- Must be required by an {@link
android.service.trust.TrustAgentService},
to ensure that only the system can bind to it. -->
- <permission android:name="android.permission.BIND_TRUST_AGENT_SERVICE"
+ <permission android:name="android.permission.BIND_TRUST_AGENT"
android:protectionLevel="signature"
android:label="@string/permlab_bind_trust_agent_service"
android:description="@string/permdesc_bind_trust_agent_service" />
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 ac75b38..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" />
@@ -6115,13 +6111,13 @@
<attr name="settingsActivity" />
</declare-styleable>
- <!-- Use <code>trust_agent</code> as the root tag of the XML resource that
+ <!-- Use <code>trust-agent</code> as the root tag of the XML resource that
describes an {@link android.service.trust.TrustAgentService}, which is
referenced from its {@link android.service.trust.TrustAgentService#TRUST_AGENT_META_DATA}
meta-data entry. Described here are the attributes that can be included in that tag. -->
<declare-styleable name="TrustAgent">
<!-- Component name of an activity that allows the user to modify
- the settings for this TrustAgent. -->
+ the settings for this trust agent. -->
<attr name="settingsActivity" />
</declare-styleable>
@@ -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/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/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/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/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java
new file mode 100644
index 0000000..0309334
--- /dev/null
+++ b/media/java/android/media/TtmlRenderer.java
@@ -0,0 +1,751 @@
+/*
+ * 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.media;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.media.SubtitleTrack.RenderingWidget.OnChangedListener;
+import android.text.Layout.Alignment;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.widget.SubtitleView;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+/** @hide */
+public class TtmlRenderer extends SubtitleController.Renderer {
+ private final Context mContext;
+
+ private static final String MEDIA_MIMETYPE_TEXT_TTML = "application/ttml+xml";
+
+ private TtmlRenderingWidget mRenderingWidget;
+
+ public TtmlRenderer(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public boolean supports(MediaFormat format) {
+ if (format.containsKey(MediaFormat.KEY_MIME)) {
+ return format.getString(MediaFormat.KEY_MIME).equals(MEDIA_MIMETYPE_TEXT_TTML);
+ }
+ return false;
+ }
+
+ @Override
+ public SubtitleTrack createTrack(MediaFormat format) {
+ if (mRenderingWidget == null) {
+ mRenderingWidget = new TtmlRenderingWidget(mContext);
+ }
+ return new TtmlTrack(mRenderingWidget, format);
+ }
+}
+
+/**
+ * A class which provides utillity methods for TTML parsing.
+ *
+ * @hide
+ */
+final class TtmlUtils {
+ public static final String TAG_TT = "tt";
+ public static final String TAG_HEAD = "head";
+ public static final String TAG_BODY = "body";
+ public static final String TAG_DIV = "div";
+ public static final String TAG_P = "p";
+ public static final String TAG_SPAN = "span";
+ public static final String TAG_BR = "br";
+ public static final String TAG_STYLE = "style";
+ public static final String TAG_STYLING = "styling";
+ public static final String TAG_LAYOUT = "layout";
+ public static final String TAG_REGION = "region";
+ public static final String TAG_METADATA = "metadata";
+ public static final String TAG_SMPTE_IMAGE = "smpte:image";
+ public static final String TAG_SMPTE_DATA = "smpte:data";
+ public static final String TAG_SMPTE_INFORMATION = "smpte:information";
+ public static final String PCDATA = "#pcdata";
+ public static final String ATTR_BEGIN = "begin";
+ public static final String ATTR_DURATION = "dur";
+ public static final String ATTR_END = "end";
+ public static final long INVALID_TIMESTAMP = Long.MAX_VALUE;
+
+ /**
+ * Time expression RE according to the spec:
+ * http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression
+ */
+ private static final Pattern CLOCK_TIME = Pattern.compile(
+ "^([0-9][0-9]+):([0-9][0-9]):([0-9][0-9])"
+ + "(?:(\\.[0-9]+)|:([0-9][0-9])(?:\\.([0-9]+))?)?$");
+
+ private static final Pattern OFFSET_TIME = Pattern.compile(
+ "^([0-9]+(?:\\.[0-9]+)?)(h|m|s|ms|f|t)$");
+
+ private TtmlUtils() {
+ }
+
+ /**
+ * Parses the given time expression and returns a timestamp in millisecond.
+ * <p>
+ * For the format of the time expression, please refer <a href=
+ * "http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression">timeExpression</a>
+ *
+ * @param time A string which includes time expression.
+ * @param frameRate the framerate of the stream.
+ * @param subframeRate the sub-framerate of the stream
+ * @param tickRate the tick rate of the stream.
+ * @return the parsed timestamp in micro-second.
+ * @throws NumberFormatException if the given string does not match to the
+ * format.
+ */
+ public static long parseTimeExpression(String time, int frameRate, int subframeRate,
+ int tickRate) throws NumberFormatException {
+ Matcher matcher = CLOCK_TIME.matcher(time);
+ if (matcher.matches()) {
+ String hours = matcher.group(1);
+ double durationSeconds = Long.parseLong(hours) * 3600;
+ String minutes = matcher.group(2);
+ durationSeconds += Long.parseLong(minutes) * 60;
+ String seconds = matcher.group(3);
+ durationSeconds += Long.parseLong(seconds);
+ String fraction = matcher.group(4);
+ durationSeconds += (fraction != null) ? Double.parseDouble(fraction) : 0;
+ String frames = matcher.group(5);
+ durationSeconds += (frames != null) ? ((double)Long.parseLong(frames)) / frameRate : 0;
+ String subframes = matcher.group(6);
+ durationSeconds += (subframes != null) ? ((double)Long.parseLong(subframes))
+ / subframeRate / frameRate
+ : 0;
+ return (long)(durationSeconds * 1000);
+ }
+ matcher = OFFSET_TIME.matcher(time);
+ if (matcher.matches()) {
+ String timeValue = matcher.group(1);
+ double value = Double.parseDouble(timeValue);
+ String unit = matcher.group(2);
+ if (unit.equals("h")) {
+ value *= 3600L * 1000000L;
+ } else if (unit.equals("m")) {
+ value *= 60 * 1000000;
+ } else if (unit.equals("s")) {
+ value *= 1000000;
+ } else if (unit.equals("ms")) {
+ value *= 1000;
+ } else if (unit.equals("f")) {
+ value = value / frameRate * 1000000;
+ } else if (unit.equals("t")) {
+ value = value / tickRate * 1000000;
+ }
+ return (long)value;
+ }
+ throw new NumberFormatException("Malformed time expression : " + time);
+ }
+
+ /**
+ * Applies <a href
+ * src="http://www.w3.org/TR/ttaf1-dfxp/#content-attribute-space">the
+ * default space policy</a> to the given string.
+ *
+ * @param in A string to apply the policy.
+ */
+ public static String applyDefaultSpacePolicy(String in) {
+ return applySpacePolicy(in, true);
+ }
+
+ /**
+ * Applies the space policy to the given string. This applies <a href
+ * src="http://www.w3.org/TR/ttaf1-dfxp/#content-attribute-space">the
+ * default space policy</a> with linefeed-treatment as treat-as-space
+ * or preserve.
+ *
+ * @param in A string to apply the policy.
+ * @param treatLfAsSpace Whether convert line feeds to spaces or not.
+ */
+ public static String applySpacePolicy(String in, boolean treatLfAsSpace) {
+ // Removes CR followed by LF. ref:
+ // http://www.w3.org/TR/xml/#sec-line-ends
+ String crRemoved = in.replaceAll("\r\n", "\n");
+ // Apply suppress-at-line-break="auto" and
+ // white-space-treatment="ignore-if-surrounding-linefeed"
+ String spacesNeighboringLfRemoved = crRemoved.replaceAll(" *\n *", "\n");
+ // Apply linefeed-treatment="treat-as-space"
+ String lfToSpace = treatLfAsSpace ? spacesNeighboringLfRemoved.replaceAll("\n", " ")
+ : spacesNeighboringLfRemoved;
+ // Apply white-space-collapse="true"
+ String spacesCollapsed = lfToSpace.replaceAll("[ \t\\x0B\f\r]+", " ");
+ return spacesCollapsed;
+ }
+
+ /**
+ * Returns the timed text for the given time period.
+ *
+ * @param root The root node of the TTML document.
+ * @param startUs The start time of the time period in microsecond.
+ * @param endUs The end time of the time period in microsecond.
+ */
+ public static String extractText(TtmlNode root, long startUs, long endUs) {
+ StringBuilder text = new StringBuilder();
+ extractText(root, startUs, endUs, text, false);
+ return text.toString().replaceAll("\n$", "");
+ }
+
+ private static void extractText(TtmlNode node, long startUs, long endUs, StringBuilder out,
+ boolean inPTag) {
+ if (node.mName.equals(TtmlUtils.PCDATA) && inPTag) {
+ out.append(node.mText);
+ } else if (node.mName.equals(TtmlUtils.TAG_BR) && inPTag) {
+ out.append("\n");
+ } else if (node.mName.equals(TtmlUtils.TAG_METADATA)) {
+ // do nothing.
+ } else if (node.isActive(startUs, endUs)) {
+ boolean pTag = node.mName.equals(TtmlUtils.TAG_P);
+ int length = out.length();
+ for (int i = 0; i < node.mChildren.size(); ++i) {
+ extractText(node.mChildren.get(i), startUs, endUs, out, pTag || inPTag);
+ }
+ if (pTag && length != out.length()) {
+ out.append("\n");
+ }
+ }
+ }
+
+ /**
+ * Returns a TTML fragment string for the given time period.
+ *
+ * @param root The root node of the TTML document.
+ * @param startUs The start time of the time period in microsecond.
+ * @param endUs The end time of the time period in microsecond.
+ */
+ public static String extractTtmlFragment(TtmlNode root, long startUs, long endUs) {
+ StringBuilder fragment = new StringBuilder();
+ extractTtmlFragment(root, startUs, endUs, fragment);
+ return fragment.toString();
+ }
+
+ private static void extractTtmlFragment(TtmlNode node, long startUs, long endUs,
+ StringBuilder out) {
+ if (node.mName.equals(TtmlUtils.PCDATA)) {
+ out.append(node.mText);
+ } else if (node.mName.equals(TtmlUtils.TAG_BR)) {
+ out.append("<br/>");
+ } else if (node.isActive(startUs, endUs)) {
+ out.append("<");
+ out.append(node.mName);
+ out.append(node.mAttributes);
+ out.append(">");
+ for (int i = 0; i < node.mChildren.size(); ++i) {
+ extractTtmlFragment(node.mChildren.get(i), startUs, endUs, out);
+ }
+ out.append("</");
+ out.append(node.mName);
+ out.append(">");
+ }
+ }
+}
+
+/**
+ * A container class which represents a cue in TTML.
+ * @hide
+ */
+class TtmlCue extends SubtitleTrack.Cue {
+ public String mText;
+ public String mTtmlFragment;
+
+ public TtmlCue(long startTimeMs, long endTimeMs, String text, String ttmlFragment) {
+ this.mStartTimeMs = startTimeMs;
+ this.mEndTimeMs = endTimeMs;
+ this.mText = text;
+ this.mTtmlFragment = ttmlFragment;
+ }
+}
+
+/**
+ * A container class which represents a node in TTML.
+ *
+ * @hide
+ */
+class TtmlNode {
+ public final String mName;
+ public final String mAttributes;
+ public final TtmlNode mParent;
+ public final String mText;
+ public final List<TtmlNode> mChildren = new ArrayList<TtmlNode>();
+ public final long mRunId;
+ public final long mStartTimeMs;
+ public final long mEndTimeMs;
+
+ public TtmlNode(String name, String attributes, String text, long startTimeMs, long endTimeMs,
+ TtmlNode parent, long runId) {
+ this.mName = name;
+ this.mAttributes = attributes;
+ this.mText = text;
+ this.mStartTimeMs = startTimeMs;
+ this.mEndTimeMs = endTimeMs;
+ this.mParent = parent;
+ this.mRunId = runId;
+ }
+
+ /**
+ * Check if this node is active in the given time range.
+ *
+ * @param startTimeMs The start time of the range to check in microsecond.
+ * @param endTimeMs The end time of the range to check in microsecond.
+ * @return return true if the given range overlaps the time range of this
+ * node.
+ */
+ public boolean isActive(long startTimeMs, long endTimeMs) {
+ return this.mEndTimeMs > startTimeMs && this.mStartTimeMs < endTimeMs;
+ }
+}
+
+/**
+ * A simple TTML parser (http://www.w3.org/TR/ttaf1-dfxp/) which supports DFXP
+ * presentation profile.
+ * <p>
+ * Supported features in this parser are:
+ * <ul>
+ * <li>content
+ * <li>core
+ * <li>presentation
+ * <li>profile
+ * <li>structure
+ * <li>time-offset
+ * <li>timing
+ * <li>tickRate
+ * <li>time-clock-with-frames
+ * <li>time-clock
+ * <li>time-offset-with-frames
+ * <li>time-offset-with-ticks
+ * </ul>
+ * </p>
+ *
+ * @hide
+ */
+class TtmlParser {
+ static final String TAG = "TtmlParser";
+
+ // TODO: read and apply the following attributes if specified.
+ private static final int DEFAULT_FRAMERATE = 30;
+ private static final int DEFAULT_SUBFRAMERATE = 1;
+ private static final int DEFAULT_TICKRATE = 1;
+
+ private XmlPullParser mParser;
+ private final TtmlNodeListener mListener;
+ private long mCurrentRunId;
+
+ public TtmlParser(TtmlNodeListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Parse TTML data. Once this is called, all the previous data are
+ * reset and it starts parsing for the given text.
+ *
+ * @param ttmlText TTML text to parse.
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ public void parse(String ttmlText, long runId) throws XmlPullParserException, IOException {
+ mParser = null;
+ mCurrentRunId = runId;
+ loadParser(ttmlText);
+ parseTtml();
+ }
+
+ private void loadParser(String ttmlFragment) throws XmlPullParserException {
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ factory.setNamespaceAware(false);
+ mParser = factory.newPullParser();
+ StringReader in = new StringReader(ttmlFragment);
+ mParser.setInput(in);
+ }
+
+ private void extractAttribute(XmlPullParser parser, int i, StringBuilder out) {
+ out.append(" ");
+ out.append(parser.getAttributeName(i));
+ out.append("=\"");
+ out.append(parser.getAttributeValue(i));
+ out.append("\"");
+ }
+
+ private void parseTtml() throws XmlPullParserException, IOException {
+ LinkedList<TtmlNode> nodeStack = new LinkedList<TtmlNode>();
+ int depthInUnsupportedTag = 0;
+ boolean active = true;
+ while (!isEndOfDoc()) {
+ int eventType = mParser.getEventType();
+ TtmlNode parent = nodeStack.peekLast();
+ if (active) {
+ if (eventType == XmlPullParser.START_TAG) {
+ if (!isSupportedTag(mParser.getName())) {
+ Log.w(TAG, "Unsupported tag " + mParser.getName() + " is ignored.");
+ depthInUnsupportedTag++;
+ active = false;
+ } else {
+ TtmlNode node = parseNode(parent);
+ nodeStack.addLast(node);
+ if (parent != null) {
+ parent.mChildren.add(node);
+ }
+ }
+ } else if (eventType == XmlPullParser.TEXT) {
+ String text = TtmlUtils.applyDefaultSpacePolicy(mParser.getText());
+ if (!TextUtils.isEmpty(text)) {
+ parent.mChildren.add(new TtmlNode(
+ TtmlUtils.PCDATA, "", text, 0, TtmlUtils.INVALID_TIMESTAMP,
+ parent, mCurrentRunId));
+
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if (mParser.getName().equals(TtmlUtils.TAG_P)) {
+ mListener.onTtmlNodeParsed(nodeStack.getLast());
+ } else if (mParser.getName().equals(TtmlUtils.TAG_TT)) {
+ mListener.onRootNodeParsed(nodeStack.getLast());
+ }
+ nodeStack.removeLast();
+ }
+ } else {
+ if (eventType == XmlPullParser.START_TAG) {
+ depthInUnsupportedTag++;
+ } else if (eventType == XmlPullParser.END_TAG) {
+ depthInUnsupportedTag--;
+ if (depthInUnsupportedTag == 0) {
+ active = true;
+ }
+ }
+ }
+ mParser.next();
+ }
+ }
+
+ private TtmlNode parseNode(TtmlNode parent) throws XmlPullParserException, IOException {
+ int eventType = mParser.getEventType();
+ if (!(eventType == XmlPullParser.START_TAG)) {
+ return null;
+ }
+ StringBuilder attrStr = new StringBuilder();
+ long start = 0;
+ long end = TtmlUtils.INVALID_TIMESTAMP;
+ long dur = 0;
+ for (int i = 0; i < mParser.getAttributeCount(); ++i) {
+ String attr = mParser.getAttributeName(i);
+ String value = mParser.getAttributeValue(i);
+ // TODO: check if it's safe to ignore the namespace of attributes as follows.
+ attr = attr.replaceFirst("^.*:", "");
+ if (attr.equals(TtmlUtils.ATTR_BEGIN)) {
+ start = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE,
+ DEFAULT_SUBFRAMERATE, DEFAULT_TICKRATE);
+ } else if (attr.equals(TtmlUtils.ATTR_END)) {
+ end = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE,
+ DEFAULT_TICKRATE);
+ } else if (attr.equals(TtmlUtils.ATTR_DURATION)) {
+ dur = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE,
+ DEFAULT_TICKRATE);
+ } else {
+ extractAttribute(mParser, i, attrStr);
+ }
+ }
+ if (parent != null) {
+ start += parent.mStartTimeMs;
+ if (end != TtmlUtils.INVALID_TIMESTAMP) {
+ end += parent.mStartTimeMs;
+ }
+ }
+ if (dur > 0) {
+ if (end != TtmlUtils.INVALID_TIMESTAMP) {
+ Log.e(TAG, "'dur' and 'end' attributes are defined at the same time." +
+ "'end' value is ignored.");
+ }
+ end = start + dur;
+ }
+ if (parent != null) {
+ // If the end time remains unspecified, then the end point is
+ // interpreted as the end point of the external time interval.
+ if (end == TtmlUtils.INVALID_TIMESTAMP &&
+ parent.mEndTimeMs != TtmlUtils.INVALID_TIMESTAMP &&
+ end > parent.mEndTimeMs) {
+ end = parent.mEndTimeMs;
+ }
+ }
+ TtmlNode node = new TtmlNode(mParser.getName(), attrStr.toString(), null, start, end,
+ parent, mCurrentRunId);
+ return node;
+ }
+
+ private boolean isEndOfDoc() throws XmlPullParserException {
+ return (mParser.getEventType() == XmlPullParser.END_DOCUMENT);
+ }
+
+ private static boolean isSupportedTag(String tag) {
+ if (tag.equals(TtmlUtils.TAG_TT) || tag.equals(TtmlUtils.TAG_HEAD) ||
+ tag.equals(TtmlUtils.TAG_BODY) || tag.equals(TtmlUtils.TAG_DIV) ||
+ tag.equals(TtmlUtils.TAG_P) || tag.equals(TtmlUtils.TAG_SPAN) ||
+ tag.equals(TtmlUtils.TAG_BR) || tag.equals(TtmlUtils.TAG_STYLE) ||
+ tag.equals(TtmlUtils.TAG_STYLING) || tag.equals(TtmlUtils.TAG_LAYOUT) ||
+ tag.equals(TtmlUtils.TAG_REGION) || tag.equals(TtmlUtils.TAG_METADATA) ||
+ tag.equals(TtmlUtils.TAG_SMPTE_IMAGE) || tag.equals(TtmlUtils.TAG_SMPTE_DATA) ||
+ tag.equals(TtmlUtils.TAG_SMPTE_INFORMATION)) {
+ return true;
+ }
+ return false;
+ }
+}
+
+/** @hide */
+interface TtmlNodeListener {
+ void onTtmlNodeParsed(TtmlNode node);
+ void onRootNodeParsed(TtmlNode node);
+}
+
+/** @hide */
+class TtmlTrack extends SubtitleTrack implements TtmlNodeListener {
+ private static final String TAG = "TtmlTrack";
+
+ private final TtmlParser mParser = new TtmlParser(this);
+ private final TtmlRenderingWidget mRenderingWidget;
+ private String mParsingData;
+ private Long mCurrentRunID;
+
+ private final LinkedList<TtmlNode> mTtmlNodes;
+ private final TreeSet<Long> mTimeEvents;
+ private TtmlNode mRootNode;
+
+ TtmlTrack(TtmlRenderingWidget renderingWidget, MediaFormat format) {
+ super(format);
+
+ mTtmlNodes = new LinkedList<TtmlNode>();
+ mTimeEvents = new TreeSet<Long>();
+ mRenderingWidget = renderingWidget;
+ mParsingData = "";
+ }
+
+ @Override
+ public TtmlRenderingWidget getRenderingWidget() {
+ return mRenderingWidget;
+ }
+
+ @Override
+ public void onData(String data, boolean eos, long runID) {
+ // implement intermixing restriction for TTML.
+ synchronized(mParser) {
+ if (mCurrentRunID != null && runID != mCurrentRunID) {
+ throw new IllegalStateException(
+ "Run #" + mCurrentRunID +
+ " in progress. Cannot process run #" + runID);
+ }
+ mCurrentRunID = runID;
+ mParsingData += data;
+ if (eos) {
+ try {
+ mParser.parse(mParsingData, mCurrentRunID);
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ finishedRun(runID);
+ mParsingData = "";
+ mCurrentRunID = null;
+ }
+ }
+ }
+
+ @Override
+ public void onTtmlNodeParsed(TtmlNode node) {
+ mTtmlNodes.addLast(node);
+ addTimeEvents(node);
+ }
+
+ @Override
+ public void onRootNodeParsed(TtmlNode node) {
+ mRootNode = node;
+ TtmlCue cue = null;
+ while ((cue = getNextResult()) != null) {
+ addCue(cue);
+ }
+ mRootNode = null;
+ mTtmlNodes.clear();
+ mTimeEvents.clear();
+ }
+
+ @Override
+ public void updateView(Vector<SubtitleTrack.Cue> activeCues) {
+ if (!mVisible) {
+ // don't keep the state if we are not visible
+ return;
+ }
+
+ if (DEBUG && mTimeProvider != null) {
+ try {
+ Log.d(TAG, "at " +
+ (mTimeProvider.getCurrentTimeUs(false, true) / 1000) +
+ " ms the active cues are:");
+ } catch (IllegalStateException e) {
+ Log.d(TAG, "at (illegal state) the active cues are:");
+ }
+ }
+
+ mRenderingWidget.setActiveCues(activeCues);
+ }
+
+ /**
+ * Returns a {@link TtmlCue} in the presentation time order.
+ * {@code null} is returned if there is no more timed text to show.
+ */
+ public TtmlCue getNextResult() {
+ while (mTimeEvents.size() >= 2) {
+ long start = mTimeEvents.pollFirst();
+ long end = mTimeEvents.first();
+ List<TtmlNode> activeCues = getActiveNodes(start, end);
+ if (!activeCues.isEmpty()) {
+ return new TtmlCue(start, end,
+ TtmlUtils.applySpacePolicy(TtmlUtils.extractText(
+ mRootNode, start, end), false),
+ TtmlUtils.extractTtmlFragment(mRootNode, start, end));
+ }
+ }
+ return null;
+ }
+
+ private void addTimeEvents(TtmlNode node) {
+ mTimeEvents.add(node.mStartTimeMs);
+ mTimeEvents.add(node.mEndTimeMs);
+ for (int i = 0; i < node.mChildren.size(); ++i) {
+ addTimeEvents(node.mChildren.get(i));
+ }
+ }
+
+ private List<TtmlNode> getActiveNodes(long startTimeUs, long endTimeUs) {
+ List<TtmlNode> activeNodes = new ArrayList<TtmlNode>();
+ for (int i = 0; i < mTtmlNodes.size(); ++i) {
+ TtmlNode node = mTtmlNodes.get(i);
+ if (node.isActive(startTimeUs, endTimeUs)) {
+ activeNodes.add(node);
+ }
+ }
+ return activeNodes;
+ }
+}
+
+/**
+ * Widget capable of rendering TTML captions.
+ *
+ * @hide
+ */
+class TtmlRenderingWidget extends LinearLayout implements SubtitleTrack.RenderingWidget {
+
+ /** Callback for rendering changes. */
+ private OnChangedListener mListener;
+ private final TextView mTextView;
+
+ public TtmlRenderingWidget(Context context) {
+ this(context, null);
+ }
+
+ public TtmlRenderingWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TtmlRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public TtmlRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ // Cannot render text over video when layer type is hardware.
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+ CaptioningManager captionManager = (CaptioningManager) context.getSystemService(
+ Context.CAPTIONING_SERVICE);
+ mTextView = new TextView(context);
+ mTextView.setTextColor(captionManager.getUserStyle().foregroundColor);
+ addView(mTextView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mTextView.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
+ }
+
+ @Override
+ public void setOnChangedListener(OnChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ measure(widthSpec, heightSpec);
+ layout(0, 0, width, height);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ }
+
+ public void setActiveCues(Vector<SubtitleTrack.Cue> activeCues) {
+ final int count = activeCues.size();
+ String subtitleText = "";
+ for (int i = 0; i < count; i++) {
+ TtmlCue cue = (TtmlCue) activeCues.get(i);
+ subtitleText += cue.mText + "\n";
+ }
+ mTextView.setText(subtitleText);
+
+ if (mListener != null) {
+ mListener.onChanged(this);
+ }
+ }
+}
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_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/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/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/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
index b48e011..b363ab4 100644
--- a/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
@@ -14,5 +14,5 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+<trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity=".SampleTrustAgentSettings" />
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
index 25406d6..a51ea75 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
@@ -31,7 +31,7 @@
LocalBroadcastManager mLocalBroadcastManager;
- private static final String ACTION_ENABLE_TRUST = "action.sample_trust_agent.enable_trust";
+ private static final String ACTION_GRANT_TRUST = "action.sample_trust_agent.grant_trust";
private static final String ACTION_REVOKE_TRUST = "action.sample_trust_agent.revoke_trust";
private static final String EXTRA_MESSAGE = "extra.message";
@@ -45,14 +45,14 @@
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_ENABLE_TRUST);
+ filter.addAction(ACTION_GRANT_TRUST);
filter.addAction(ACTION_REVOKE_TRUST);
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.registerReceiver(mReceiver, filter);
}
@Override
- protected void onUnlockAttempt(boolean successful) {
+ public void onUnlockAttempt(boolean successful) {
if (getReportUnlockAttempts(this)) {
Toast.makeText(this, "onUnlockAttempt(successful=" + successful + ")",
Toast.LENGTH_SHORT).show();
@@ -69,8 +69,8 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (ACTION_ENABLE_TRUST.equals(action)) {
- enableTrust(intent.getStringExtra(EXTRA_MESSAGE),
+ if (ACTION_GRANT_TRUST.equals(action)) {
+ grantTrust(intent.getStringExtra(EXTRA_MESSAGE),
intent.getLongExtra(EXTRA_DURATION, 0),
false /* initiatedByUser */);
} else if (ACTION_REVOKE_TRUST.equals(action)) {
@@ -79,9 +79,9 @@
}
};
- public static void sendEnableTrust(Context context,
+ public static void sendGrantTrust(Context context,
String message, long durationMs, Bundle extra) {
- Intent intent = new Intent(ACTION_ENABLE_TRUST);
+ Intent intent = new Intent(ACTION_GRANT_TRUST);
intent.putExtra(EXTRA_MESSAGE, message);
intent.putExtra(EXTRA_DURATION, durationMs);
intent.putExtra(EXTRA_EXTRA, extra);
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
index 0a6f675..8e293fb 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
-import android.preference.CheckBoxPreference;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -53,7 +52,7 @@
public void onClick(View v) {
int id = v.getId();
if (id == R.id.enable_trust) {
- SampleTrustAgent.sendEnableTrust(this, "SampleTrustAgent", TRUST_DURATION_MS,
+ SampleTrustAgent.sendGrantTrust(this, "SampleTrustAgent", TRUST_DURATION_MS,
null /* extra */);
} else if (id == R.id.revoke_trust) {
SampleTrustAgent.sendRevokeTrust(this);
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_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-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-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-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-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_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_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_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..45b5548 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:fill="#FFFFFFFF"
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"/>
</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..6d44406 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:fill="#FFFFFFFF"
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"/>
</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%
rename from packages/SystemUI/res/drawable/ic_qs_zen.xml
rename 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/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/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..b3829a3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -553,6 +553,9 @@
<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>
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/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..bfd416d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -51,21 +51,25 @@
}
@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.iconId = R.drawable.ic_qs_bugreport;
state.label = mContext.getString(com.android.internal.R.string.bugreport_title);
}
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/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/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..c1228d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -428,14 +428,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) {
@@ -875,6 +877,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 +1040,8 @@
if (DEBUG) {
Log.d(TAG, "addNotificationViews: added at " + pos);
}
- updateRowStates();
updateNotificationIcons();
+ updateRowStates();
}
private void addNotificationViews(IBinder key, StatusBarNotification notification) {
@@ -1058,6 +1061,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 +1089,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 +1100,8 @@
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
}
+
+ mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
}
private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1307,9 +1317,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/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/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..a685073 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;
@@ -618,7 +619,7 @@
mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
mNotificationIcons.setOverflowIndicator(mMoreIcon);
mModeIcon = (ImageView)mStatusBarView.findViewById(R.id.modeIcon);
- mModeIcon.setImageResource(R.drawable.stat_sys_zen_limited);
+ mModeIcon.setImageResource(R.drawable.ic_qs_zen_on);
mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
mTickerView = mStatusBarView.findViewById(R.id.ticker);
@@ -634,6 +635,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 +1155,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);
}
}
@@ -2560,13 +2565,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 +2587,7 @@
}
public void startSettingsActivity(String action) {
- postStartSettingsActivity(new Intent(action));
+ postStartSettingsActivity(new Intent(action), 0);
}
private static class FastColorDrawable extends Drawable {
@@ -2722,7 +2727,7 @@
setBarState(StatusBarState.SHADE);
if (mLeaveOpenOnKeyguardHide) {
mLeaveOpenOnKeyguardHide = false;
- mNotificationPanel.animateNextTopPaddingChange();
+ mNotificationPanel.animateToFullShade();
} else {
instantCollapseNotificationPanel();
}
@@ -2894,7 +2899,7 @@
mLeaveOpenOnKeyguardHide = true;
showBouncer();
} else {
- mNotificationPanel.animateNextTopPaddingChange();
+ mNotificationPanel.animateToFullShade();
setBarState(StatusBarState.SHADE_LOCKED);
updateKeyguardState();
}
@@ -2917,4 +2922,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/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/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..5f53e49 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -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;
@@ -3216,6 +3219,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 " +
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/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/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index fc6183c..6d2b83b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -58,14 +58,14 @@
}
/**
- * Build <Get Osd Name> command.
+ * Build <Give Osd Name> command.
*
* @param src source address of command
* @param dest destination address of command
* @return newly created {@link HdmiCecMessage}
*/
- static HdmiCecMessage buildGetOsdNameCommand(int src, int dest) {
- return buildCommand(src, dest, HdmiCec.MESSAGE_GET_OSD_NAME);
+ static HdmiCecMessage buildGiveOsdNameCommand(int src, int dest) {
+ return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_OSD_NAME);
}
/**
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c122645..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.");
}
@@ -127,8 +130,8 @@
case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
handleGetMenuLanguage(message);
return true;
- case HdmiCec.MESSAGE_GET_OSD_NAME:
- handleGetOsdName(message);
+ case HdmiCec.MESSAGE_GIVE_OSD_NAME:
+ handleGiveOsdName(message);
return true;
case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
handleGivePhysicalAddress(message);
@@ -170,7 +173,7 @@
sendCecCommand(cecMessage);
}
- private void handleGetOsdName(HdmiCecMessage message) {
+ private void handleGiveOsdName(HdmiCecMessage message) {
// TODO: read device name from settings or property.
String name = HdmiCec.getDefaultDeviceName(message.getDestination());
HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 98da280..e0bc718 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -71,7 +71,7 @@
@Override
public boolean start() {
sendCommand(
- HdmiCecMessageBuilder.buildGetOsdNameCommand(mSourceAddress,
+ HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress,
mDeviceLogicalAddress));
mState = STATE_WAITING_FOR_SET_OSD_NAME;
addTimer(mState, TIMEOUT_MS);
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/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/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index a83fa87..d8d3da1 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -52,7 +52,7 @@
// Trust state
private boolean mTrusted;
- private String mMessage;
+ private CharSequence mMessage;
private final Handler mHandler = new Handler() {
@Override
@@ -60,7 +60,7 @@
switch (msg.what) {
case MSG_ENABLE_TRUST:
mTrusted = true;
- mMessage = (String) msg.obj;
+ mMessage = (CharSequence) msg.obj;
boolean initiatedByUser = msg.arg1 != 0;
// TODO: Handle handle user initiated trust changes.
mTrustManagerService.updateTrust(mUserId);
@@ -79,7 +79,8 @@
private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
- public void enableTrust(String userMessage, long durationMs, boolean initiatedByUser) {
+ @Override
+ public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
+ ", initiatedByUser = " + initiatedByUser + ")");
@@ -91,6 +92,7 @@
}
}
+ @Override
public void revokeTrust() {
if (DEBUG) Slog.v(TAG, "revokeTrust()");
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
@@ -155,7 +157,7 @@
return mTrusted;
}
- public String getMessage() {
+ public CharSequence getMessage() {
return mMessage;
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 9061f96..c1b9a33 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -24,11 +24,14 @@
import org.xmlpull.v1.XmlPullParserException;
import android.Manifest;
+import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustListener;
import android.app.trust.ITrustManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
@@ -46,6 +49,7 @@
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.util.Xml;
import java.io.IOException;
@@ -81,6 +85,8 @@
private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+ private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver();
+ private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
private final Context mContext;
private UserManager mUserManager;
@@ -105,8 +111,8 @@
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
- // Listen for package changes
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+ mDevicePolicyReceiver.register(mContext);
refreshAgentList();
}
}
@@ -158,8 +164,13 @@
mObsoleteAgents.addAll(mActiveAgents);
for (UserInfo userInfo : userInfos) {
+ int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
+ .getKeyguardDisabledFeatures(null, userInfo.id);
+ boolean disableTrustAgents =
+ (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+
List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
- if (enabledAgents == null) {
+ if (disableTrustAgents || enabledAgents == null) {
continue;
}
List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
@@ -221,8 +232,8 @@
// Drain preamble.
}
String nodeName = parser.getName();
- if (!"trust_agent".equals(nodeName)) {
- Slog.w(TAG, "Meta-data does not start with trust_agent tag");
+ if (!"trust-agent".equals(nodeName)) {
+ Slog.w(TAG, "Meta-data does not start with trust-agent tag");
return null;
}
TypedArray sa = res
@@ -259,6 +270,9 @@
// Agent dispatch and aggregation
private boolean aggregateIsTrusted(int userId) {
+ if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
+ return false;
+ }
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo info = mActiveAgents.valueAt(i);
if (info.userId == userId) {
@@ -277,6 +291,11 @@
info.agent.onUnlockAttempt(successful);
}
}
+
+ if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) {
+ mUserHasAuthenticatedSinceBoot.put(userId, true);
+ updateTrust(userId);
+ }
}
// Listeners
@@ -384,4 +403,24 @@
return true;
}
};
+
+ private class DevicePolicyReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
+ intent.getAction())) {
+ refreshAgentList();
+ }
+ }
+
+ public void register(Context context) {
+ context.registerReceiverAsUser(this,
+ UserHandle.ALL,
+ new IntentFilter(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+ null /* permission */,
+ null /* scheduler */);
+ }
+ }
}
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index 6e03993..1d111a1 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -142,7 +142,7 @@
// Handles incoming <Request Active Source> message. If one of logical
// devices is active, it should reply with <Active Source> message.
void handleRequestActiveSource();
- void handleGetOsdName(const cec_message_t& msg);
+ void handleGiveOsdName(const cec_message_t& msg);
void handleGiveDeviceVendorID(const cec_message_t& msg);
void handleGetCECVersion(const cec_message_t& msg);
void handleGetMenuLanguage(const cec_message_t& msg);
@@ -555,8 +555,8 @@
sendReportPhysicalAddress(msg.destination);
} else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) {
handleRequestActiveSource();
- } else if (opcode == CEC_MESSAGE_GET_OSD_NAME) {
- handleGetOsdName(msg);
+ } else if (opcode == CEC_MESSAGE_GIVE_OSD_NAME) {
+ handleGiveOsdName(msg);
} else if (opcode == CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID) {
handleGiveDeviceVendorID(msg);
} else if (opcode == CEC_MESSAGE_GET_CEC_VERSION) {
@@ -631,7 +631,7 @@
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-void HdmiCecHandler::handleGetOsdName(const cec_message_t& msg) {
+void HdmiCecHandler::handleGiveOsdName(const cec_message_t& msg) {
if (!mOsdName.empty()) {
sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length());
}
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/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7002744..2bf9ef1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1773,12 +1773,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 +1793,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 +1814,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 +1832,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) {
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 72398ad..8b80bfa 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -373,6 +373,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.
*
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/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%
rename from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
rename 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%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy 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];
+ }
+ };
+}