Merge "Move inputservice over to frameworks/native"
diff --git a/api/current.txt b/api/current.txt
index a0a4e91..d7b4ef5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4771,6 +4771,7 @@
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isDeviceOwnerApp(java.lang.String);
+ method public boolean isProfileOwnerApp(java.lang.String);
method public void lockNow();
method public void removeActiveAdmin(android.content.ComponentName);
method public boolean resetPassword(java.lang.String, int);
@@ -11271,28 +11272,37 @@
field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES;
field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
+ field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_HYPERFOCAL_DISTANCE;
field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE;
field public static final android.hardware.camera2.CameraMetadata.Key LENS_INFO_SHADING_MAP_SIZE;
+ field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_AVAILABLE_CAPABILITIES;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_INPUT_STREAMS;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_FORMATS;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_MIN_DURATIONS;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STALL_DURATIONS;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BLACK_LEVEL_PATTERN;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_EXPOSURE_TIME_RANGE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_MAX_FRAME_DURATION;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PHYSICAL_SIZE;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_PIXEL_ARRAY_SIZE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_SENSITIVITY_RANGE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_MAX_FACE_COUNT;
field public static final android.hardware.camera2.CameraMetadata.Key SYNC_MAX_LATENCY;
@@ -11424,6 +11434,7 @@
field public static final int CONTROL_EFFECT_MODE_WHITEBOARD = 6; // 0x6
field public static final int CONTROL_MODE_AUTO = 1; // 0x1
field public static final int CONTROL_MODE_OFF = 0; // 0x0
+ field public static final int CONTROL_MODE_OFF_KEEP_STATE = 3; // 0x3
field public static final int CONTROL_MODE_USE_SCENE_MODE = 2; // 0x2
field public static final int CONTROL_SCENE_MODE_ACTION = 2; // 0x2
field public static final int CONTROL_SCENE_MODE_BARCODE = 16; // 0x10
@@ -11452,10 +11463,16 @@
field public static final int FLASH_STATE_FIRED = 3; // 0x3
field public static final int FLASH_STATE_READY = 2; // 0x2
field public static final int FLASH_STATE_UNAVAILABLE = 0; // 0x0
+ field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
+ field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
+ field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
field public static final int LENS_FACING_BACK = 1; // 0x1
field public static final int LENS_FACING_FRONT = 0; // 0x0
+ field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1; // 0x1
+ field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2; // 0x2
+ field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0; // 0x0
field public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0; // 0x0
field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
field public static final int LENS_STATE_MOVING = 1; // 0x1
@@ -11463,6 +11480,11 @@
field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
+ field public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // 0x5
+ field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2; // 0x2
+ field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4
+ field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; // 0x1
+ field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0; // 0x0
field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS = 2; // 0x2
field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY = 3; // 0x3
field public static final int SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256; // 0x100
@@ -11530,6 +11552,7 @@
field public static final android.os.Parcelable.Creator CREATOR;
field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
@@ -11587,6 +11610,8 @@
field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE;
+ field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MAP;
+ field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES;
field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD;
field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_TIMESTAMP;
@@ -11605,8 +11630,14 @@
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_FRAME_COUNT;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_DEPTH;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_CROP_REGION;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_CALIBRATION_TRANSFORM;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_COLOR_TRANSFORM;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
@@ -28631,6 +28662,7 @@
method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
method public void createContextMenu(android.view.ContextMenu);
method public void destroyDrawingCache();
+ method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
method public void dispatchConfigurationChanged(android.content.res.Configuration);
method public void dispatchDisplayHint(int);
method public boolean dispatchDragEvent(android.view.DragEvent);
@@ -28662,7 +28694,7 @@
method public final android.view.View findViewById(int);
method public final android.view.View findViewWithTag(java.lang.Object);
method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
- method protected boolean fitSystemWindows(android.graphics.Rect);
+ method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
method public android.view.View focusSearch(int);
method public void forceLayout();
method public static int generateViewId();
@@ -28848,6 +28880,7 @@
method public void offsetTopAndBottom(int);
method protected void onAnimationEnd();
method protected void onAnimationStart();
+ method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
method protected void onAttachedToWindow();
method public void onCancelPendingInputEvents();
method public boolean onCheckIsTextEditor();
@@ -28914,7 +28947,8 @@
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
- method public void requestFitSystemWindows();
+ method public void requestApplyInsets();
+ method public deprecated void requestFitSystemWindows();
method public final boolean requestFocus();
method public final boolean requestFocus(int);
method public boolean requestFocus(int, android.graphics.Rect);
@@ -28978,6 +29012,7 @@
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
+ method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
method public void setOnDragListener(android.view.View.OnDragListener);
@@ -29199,6 +29234,10 @@
field public static final int UNSPECIFIED = 0; // 0x0
}
+ public static abstract interface View.OnApplyWindowInsetsListener {
+ method public abstract android.view.WindowInsets onApplyWindowInsets(android.view.View, android.view.WindowInsets);
+ }
+
public static abstract interface View.OnAttachStateChangeListener {
method public abstract void onViewAttachedToWindow(android.view.View);
method public abstract void onViewDetachedFromWindow(android.view.View);
@@ -29818,6 +29857,27 @@
method public abstract void onFocusLost(android.view.WindowId);
}
+ public class WindowInsets {
+ ctor public WindowInsets(android.view.WindowInsets);
+ method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
+ method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
+ method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
+ method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
+ method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
+ method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+ method public int getSystemWindowInsetBottom();
+ method public int getSystemWindowInsetLeft();
+ method public int getSystemWindowInsetRight();
+ method public int getSystemWindowInsetTop();
+ method public int getWindowDecorInsetBottom();
+ method public int getWindowDecorInsetLeft();
+ method public int getWindowDecorInsetRight();
+ method public int getWindowDecorInsetTop();
+ method public boolean hasInsets();
+ method public boolean hasSystemWindowInsets();
+ method public boolean hasWindowDecorInsets();
+ }
+
public abstract interface WindowManager implements android.view.ViewManager {
method public abstract android.view.Display getDefaultDisplay();
method public abstract void removeViewImmediate(android.view.View);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index df4ec78..8acd19b 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.SurfaceTexture;
@@ -43,6 +44,10 @@
private int mHeight;
private Surface mSurface;
+ // Only one IIntentSender or Intent may be queued at a time. Most recent one wins.
+ IIntentSender mQueuedPendingIntent;
+ Intent mQueuedIntent;
+
public ActivityView(Context context) {
this(context, null);
}
@@ -72,7 +77,7 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mTextureView.layout(l, t, r, b);
+ mTextureView.layout(0, 0, r - l, b - t);
}
@Override
@@ -118,28 +123,38 @@
} catch (RemoteException e) {
throw new IllegalStateException("ActivityView: Unable to startActivity. " + e);
}
+ } else {
+ mQueuedIntent = intent;
+ mQueuedPendingIntent = null;
+ }
+ }
+
+ private void startActivityIntentSender(IIntentSender iIntentSender) {
+ try {
+ mActivityContainer.startActivityIntentSender(iIntentSender);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "ActivityView: Unable to startActivity from IntentSender. " + e);
}
}
public void startActivity(IntentSender intentSender) {
+ final IIntentSender iIntentSender = intentSender.getTarget();
if (mSurface != null) {
- try {
- mActivityContainer.startActivityIntentSender(intentSender.getTarget());
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "ActivityView: Unable to startActivity from IntentSender. " + e);
- }
+ startActivityIntentSender(iIntentSender);
+ } else {
+ mQueuedPendingIntent = iIntentSender;
+ mQueuedIntent = null;
}
}
public void startActivity(PendingIntent pendingIntent) {
+ final IIntentSender iIntentSender = pendingIntent.getTarget();
if (mSurface != null) {
- try {
- mActivityContainer.startActivityIntentSender(pendingIntent.getTarget());
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "ActivityView: Unable to startActivity from PendingIntent. " + e);
- }
+ startActivityIntentSender(iIntentSender);
+ } else {
+ mQueuedPendingIntent = iIntentSender;
+ mQueuedIntent = null;
}
}
@@ -163,6 +178,14 @@
throw new IllegalStateException(
"ActivityView: Unable to create ActivityContainer. " + e);
}
+
+ if (mQueuedIntent != null) {
+ startActivity(mQueuedIntent);
+ mQueuedIntent = null;
+ } else if (mQueuedPendingIntent != null) {
+ startActivityIntentSender(mQueuedPendingIntent);
+ mQueuedPendingIntent = null;
+ }
}
private void detach() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ab82531..40bdb73 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -26,6 +26,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Handler;
+import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -1681,4 +1682,88 @@
}
return null;
}
+
+ /**
+ * @hide
+ * Sets the given package as the profile owner of the given user profile. The package must
+ * already be installed and there shouldn't be an existing profile owner registered for this
+ * user. Also, this method must be called before the user has been used for the first time.
+ * @param packageName the package name of the application to be registered as profile owner.
+ * @param ownerName the human readable name of the organisation associated with this DPM.
+ * @return whether the package was successfully registered as the profile owner.
+ * @throws IllegalArgumentException if packageName is null, the package isn't installed, or
+ * the user has already been set up.
+ */
+ public boolean setProfileOwner(String packageName, String ownerName)
+ throws IllegalArgumentException {
+ if (mService != null) {
+ try {
+ return mService.setProfileOwner(packageName, ownerName,
+ Process.myUserHandle().getIdentifier());
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to set profile owner", re);
+ throw new IllegalArgumentException("Couldn't set profile owner.", re);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Used to determine if a particular package is registered as the Profile Owner for the
+ * current user. A profile owner is a special device admin that has additional priviledges
+ * within the managed profile.
+ *
+ * @param packageName The package name of the app to compare with the registered profile owner.
+ * @return Whether or not the package is registered as the profile owner.
+ */
+ public boolean isProfileOwnerApp(String packageName) {
+ if (mService != null) {
+ try {
+ String profileOwnerPackage = mService.getProfileOwner(
+ Process.myUserHandle().getIdentifier());
+ return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to check profile owner");
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ * @return the packageName of the owner of the given user profile or null if no profile
+ * owner has been set for that user.
+ * @throws IllegalArgumentException if the userId is invalid.
+ */
+ public String getProfileOwner() throws IllegalArgumentException {
+ if (mService != null) {
+ try {
+ return mService.getProfileOwner(Process.myUserHandle().getIdentifier());
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to get profile owner");
+ throw new IllegalArgumentException(
+ "Requested profile owner for invalid userId", re);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @hide
+ * @return the human readable name of the organisation associated with this DPM or null if
+ * one is not set.
+ * @throws IllegalArgumentException if the userId is invalid.
+ */
+ public String getProfileOwnerName() throws IllegalArgumentException {
+ if (mService != null) {
+ try {
+ return mService.getProfileOwnerName(Process.myUserHandle().getIdentifier());
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to get profile owner");
+ throw new IllegalArgumentException(
+ "Requested profile owner for invalid userId", re);
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 172c47c..9d189db 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -103,6 +103,10 @@
String getDeviceOwner();
String getDeviceOwnerName();
+ boolean setProfileOwner(String packageName, String ownerName, int userHandle);
+ String getProfileOwner(int userHandle);
+ String getProfileOwnerName(int userHandle);
+
boolean installCaCert(in byte[] certBuffer);
void uninstallCaCert(in byte[] certBuffer);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index aa96f0e..de00f71 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1625,10 +1625,7 @@
String locale = null;
if (mConfiguration.locale != null) {
- locale = mConfiguration.locale.getLanguage();
- if (mConfiguration.locale.getCountry() != null) {
- locale += "-" + mConfiguration.locale.getCountry();
- }
+ locale = mConfiguration.locale.toLanguageTag();
}
int width, height;
if (mMetrics.widthPixels >= mMetrics.heightPixels) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 913b273..3672de4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -284,16 +284,16 @@
* <li>The sizes will be sorted by increasing pixel area (width x height).
* If several resolutions have the same area, they will be sorted by increasing width.</li>
* <li>The aspect ratio of the largest thumbnail size will be same as the
- * aspect ratio of largest size in {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES android.scaler.availableJpegSizes}.
+ * aspect ratio of largest JPEG output size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.
* The largest size is defined as the size that has the largest pixel area
* in a given size list.</li>
- * <li>Each size in {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES android.scaler.availableJpegSizes} will have at least
+ * <li>Each output JPEG size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} will have at least
* one corresponding size that has the same aspect ratio in availableThumbnailSizes,
* and vice versa.</li>
* <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
* </ul>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
*/
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);
@@ -348,19 +348,22 @@
new Key<byte[]>("android.lens.info.availableOpticalStabilization", byte[].class);
/**
- * <p>Hyperfocal distance for this lens; set to
- * 0 if fixed focus</p>
- * <p>The hyperfocal distance is used for the old
- * API's 'fixed' setting</p>
+ * <p>Optional. Hyperfocal distance for this lens.</p>
+ * <p>If the lens is fixed focus, the camera device will report 0.</p>
+ * <p>If the lens is not fixed focus, the camera device will report this
+ * field when {@link CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION android.lens.info.focusDistanceCalibration} is APPROXIMATE or CALIBRATED.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
*/
public static final Key<Float> LENS_INFO_HYPERFOCAL_DISTANCE =
new Key<Float>("android.lens.info.hyperfocalDistance", float.class);
/**
* <p>Shortest distance from frontmost surface
- * of the lens that can be focused correctly</p>
+ * of the lens that can be focused correctly.</p>
* <p>If the lens is fixed-focus, this should be
- * 0</p>
+ * 0.</p>
*/
public static final Key<Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE =
new Key<Float>("android.lens.info.minimumFocusDistance", float.class);
@@ -374,6 +377,24 @@
new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
/**
+ * <p>The lens focus distance calibration quality.</p>
+ * <p>The lens focus distance calibration quality determines the reliability of
+ * focus related metadata entries, i.e. {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+ * {@link CaptureResult#LENS_FOCUS_RANGE android.lens.focusRange}, {@link CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE android.lens.info.hyperfocalDistance}, and
+ * {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}.</p>
+ *
+ * @see CaptureRequest#LENS_FOCUS_DISTANCE
+ * @see CaptureResult#LENS_FOCUS_RANGE
+ * @see CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE
+ * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
+ * @see #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED
+ * @see #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE
+ * @see #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED
+ */
+ public static final Key<Integer> LENS_INFO_FOCUS_DISTANCE_CALIBRATION =
+ new Key<Integer>("android.lens.info.focusDistanceCalibration", int.class);
+
+ /**
* <p>Direction the camera faces relative to
* device screen</p>
* @see #LENS_FACING_FRONT
@@ -473,8 +494,100 @@
new Key<Integer>("android.request.partialResultCount", int.class);
/**
+ * <p>List of capabilities that the camera device
+ * advertises as fully supporting.</p>
+ * <p>A capability is a contract that the camera device makes in order
+ * to be able to satisfy one or more use cases.</p>
+ * <p>Listing a capability guarantees that the whole set of features
+ * required to support a common use will all be available.</p>
+ * <p>Using a subset of the functionality provided by an unsupported
+ * capability may be possible on a specific camera device implementation;
+ * to do this query each of android.request.availableRequestKeys,
+ * android.request.availableResultKeys,
+ * android.request.availableCharacteristicsKeys.</p>
+ * <p>XX: Maybe these should go into android.info.supportedHardwareLevel
+ * as a table instead?</p>
+ * <p>The following capabilities are guaranteed to be available on
+ * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL devices:</p>
+ * <ul>
+ * <li>MANUAL_SENSOR</li>
+ * <li>ZSL</li>
+ * </ul>
+ * <p>Other capabilities may be available on either FULL or LIMITED
+ * devices, but the app. should query this field to be sure.</p>
+ *
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_GCAM
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_ZSL
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_DNG
+ */
+ public static final Key<Integer> REQUEST_AVAILABLE_CAPABILITIES =
+ new Key<Integer>("android.request.availableCapabilities", int.class);
+
+ /**
+ * <p>A list of all keys that the camera device has available
+ * to use with CaptureRequest.</p>
+ * <p>Attempting to set a key into a CaptureRequest that is not
+ * listed here will result in an invalid request and will be rejected
+ * by the camera device.</p>
+ * <p>This field can be used to query the feature set of a camera device
+ * at a more granular level than capabilities. This is especially
+ * important for optional keys that are not listed under any capability
+ * in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+ * <p>TODO: This should be used by #getAvailableCaptureRequestKeys.</p>
+ *
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
+ */
+ public static final Key<int[]> REQUEST_AVAILABLE_REQUEST_KEYS =
+ new Key<int[]>("android.request.availableRequestKeys", int[].class);
+
+ /**
+ * <p>A list of all keys that the camera device has available
+ * to use with CaptureResult.</p>
+ * <p>Attempting to get a key from a CaptureResult that is not
+ * listed here will always return a <code>null</code> value. Getting a key from
+ * a CaptureResult that is listed here must never return a <code>null</code>
+ * value.</p>
+ * <p>The following keys may return <code>null</code> unless they are enabled:</p>
+ * <ul>
+ * <li>{@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} (non-null iff {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} == ON)</li>
+ * </ul>
+ * <p>(Those sometimes-null keys should nevertheless be listed here
+ * if they are available.)</p>
+ * <p>This field can be used to query the feature set of a camera device
+ * at a more granular level than capabilities. This is especially
+ * important for optional keys that are not listed under any capability
+ * in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+ * <p>TODO: This should be used by #getAvailableCaptureResultKeys.</p>
+ *
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+ * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+ * @hide
+ */
+ public static final Key<int[]> REQUEST_AVAILABLE_RESULT_KEYS =
+ new Key<int[]>("android.request.availableResultKeys", int[].class);
+
+ /**
+ * <p>A list of all keys that the camera device has available
+ * to use with CameraCharacteristics.</p>
+ * <p>This entry follows the same rules as
+ * android.request.availableResultKeys (except that it applies for
+ * CameraCharacteristics instead of CaptureResult). See above for more
+ * details.</p>
+ * <p>TODO: This should be used by CameraCharacteristics#getKeys.</p>
+ * @hide
+ */
+ public static final Key<int[]> REQUEST_AVAILABLE_CHARACTERISTICS_KEYS =
+ new Key<int[]>("android.request.availableCharacteristicsKeys", int[].class);
+
+ /**
* <p>The list of image formats that are supported by this
- * camera device.</p>
+ * camera device for output streams.</p>
* <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
* <p>When set to YUV_420_888, application can access the YUV420 data directly.</p>
*/
@@ -549,6 +662,240 @@
new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
/**
+ * <p>The mapping of image formats that are supported by this
+ * camera device for input streams, to their corresponding output formats.</p>
+ * <p>All camera devices with at least 1
+ * android.request.request.maxNumInputStreams will have at least one
+ * available input format.</p>
+ * <p>The camera device will support the following map of formats,
+ * if its dependent capability is supported:</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="left">Input Format</th>
+ * <th align="left">Output Format</th>
+ * <th align="left">Capability</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="left">RAW_OPAQUE</td>
+ * <td align="left">JPEG</td>
+ * <td align="left">ZSL</td>
+ * </tr>
+ * <tr>
+ * <td align="left">RAW_OPAQUE</td>
+ * <td align="left">YUV_420_888</td>
+ * <td align="left">ZSL</td>
+ * </tr>
+ * <tr>
+ * <td align="left">RAW_OPAQUE</td>
+ * <td align="left">RAW16</td>
+ * <td align="left">DNG</td>
+ * </tr>
+ * <tr>
+ * <td align="left">RAW16</td>
+ * <td align="left">YUV_420_888</td>
+ * <td align="left">DNG</td>
+ * </tr>
+ * <tr>
+ * <td align="left">RAW16</td>
+ * <td align="left">JPEG</td>
+ * <td align="left">DNG</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>For ZSL-capable camera devices, using the RAW_OPAQUE format
+ * as either input or output will never hurt maximum frame rate (i.e.
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} will not have RAW_OPAQUE).</p>
+ * <p>Attempting to configure an input stream with output streams not
+ * listed as available in this map is not valid.</p>
+ * <p>TODO: Add java type mapping for this property.</p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ */
+ public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
+ new Key<int[]>("android.scaler.availableInputOutputFormatsMap", int[].class);
+
+ /**
+ * <p>The available stream configurations that this
+ * camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ * <p>The configurations are listed as <code>(format, width, height, input?)</code>
+ * tuples.</p>
+ * <p>All camera devices will support sensor maximum resolution (defined by
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) for the JPEG format.</p>
+ * <p>For a given use case, the actual maximum supported resolution
+ * may be lower than what is listed here, depending on the destination
+ * Surface for the image data. For example, for recording video,
+ * the video encoder chosen may have a maximum size limit (e.g. 1080p)
+ * smaller than what the camera (e.g. maximum resolution is 3264x2448)
+ * 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
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP 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>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">Format</th>
+ * <th align="center">Size</th>
+ * <th align="center">Hardware Level</th>
+ * <th align="center">Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+ * <td align="center">Any</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">1920x1080 (1080p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 1080p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">1280x720 (720)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 720p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">640x480 (480p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 480p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">320x240 (240p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 240p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">YUV_420_888</td>
+ * <td align="center">all output sizes available for JPEG</td>
+ * <td align="center">FULL</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">YUV_420_888</td>
+ * <td align="center">all output sizes available for JPEG, up to the maximum video size</td>
+ * <td align="center">LIMITED</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">IMPLEMENTATION_DEFINED</td>
+ * <td align="center">same as YUV_420_888</td>
+ * <td align="center">Any</td>
+ * <td align="center"></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional
+ * mandatory stream configurations on a per-capability basis.</p>
+ *
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
+ * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT
+ */
+ public static final Key<int[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS =
+ new Key<int[]>("android.scaler.availableStreamConfigurations", int[].class);
+
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination.</p>
+ * <p>This should correspond to the frame duration when only that
+ * stream is active, with all processing (typically in android.*.mode)
+ * set to either OFF or FAST.</p>
+ * <p>When multiple streams are used in a request, the minimum frame
+ * duration will be max(individual stream min durations).</p>
+ * <p>The minimum frame duration of a stream (of a particular format, size)
+ * is the same regardless of whether the stream is input or output.</p>
+ * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} for more details about
+ * calculating the max frame rate.</p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ */
+ public static final Key<long[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS =
+ new Key<long[]>("android.scaler.availableMinFrameDurations", long[].class);
+
+ /**
+ * <p>This lists the maximum stall duration for each
+ * format/size combination.</p>
+ * <p>A stall duration is how much extra time would get added
+ * to the normal minimum frame duration for a repeating request
+ * that has streams with non-zero stall.</p>
+ * <p>For example, consider JPEG captures which have the following
+ * characteristics:</p>
+ * <ul>
+ * <li>JPEG streams act like processed YUV streams in requests for which
+ * they are not included; in requests in which they are directly
+ * referenced, they act as JPEG streams. This is because supporting a
+ * JPEG stream requires the underlying YUV data to always be ready for
+ * use by a JPEG encoder, but the encoder will only be used (and impact
+ * frame duration) on requests that actually reference a JPEG stream.</li>
+ * <li>The JPEG processor can run concurrently to the rest of the camera
+ * pipeline, but cannot process more than 1 capture at a time.</li>
+ * </ul>
+ * <p>In other words, using a repeating YUV request would result
+ * in a steady frame rate (let's say it's 30 FPS). If a single
+ * JPEG request is submitted periodically, the frame rate will stay
+ * at 30 FPS (as long as we wait for the previous JPEG to return each
+ * time). If we try to submit a repeating YUV + JPEG request, then
+ * the frame rate will drop from 30 FPS.</p>
+ * <p>In general, submitting a new request with a non-0 stall time
+ * stream will <em>not</em> cause a frame rate drop unless there are still
+ * outstanding buffers for that stream from previous requests.</p>
+ * <p>Submitting a repeating request with streams (call this <code>S</code>)
+ * is the same as setting the minimum frame duration from
+ * the normal minimum frame duration corresponding to <code>S</code>, added with
+ * the maximum stall duration for <code>S</code>.</p>
+ * <p>If interleaving requests with and without a stall duration,
+ * a request will stall by the maximum of the remaining times
+ * for each can-stall stream with outstanding buffers.</p>
+ * <p>This means that a stalling request will not have an exposure start
+ * until the stall has completed.</p>
+ * <p>This should correspond to the stall duration when only that stream is
+ * active, with all processing (typically in android.*.mode) set to FAST
+ * or OFF. Setting any of the processing modes to HIGH_QUALITY
+ * effectively results in an indeterminate stall duration for all
+ * streams in a request (the regular stall calculation rules are
+ * ignored).</p>
+ * <p>The following formats may always have a stall duration:</p>
+ * <ul>
+ * <li>JPEG</li>
+ * <li>RAW16</li>
+ * </ul>
+ * <p>The following formats will never have a stall duration:</p>
+ * <ul>
+ * <li>YUV_420_888</li>
+ * <li>IMPLEMENTATION_DEFINED</li>
+ * </ul>
+ * <p>All other formats may or may not have an allowed stall duration on
+ * a per-capability basis; refer to android.request.availableCapabilities
+ * for more details.</p>
+ * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about
+ * calculating the max frame rate (absent stalls).</p>
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ */
+ public static final Key<long[]> SCALER_AVAILABLE_STALL_DURATIONS =
+ new Key<long[]>("android.scaler.availableStallDurations", long[].class);
+
+ /**
* <p>Area of raw data which corresponds to only
* active pixels.</p>
* <p>It is smaller or equal to
@@ -601,6 +948,16 @@
new Key<float[]>("android.sensor.info.physicalSize", float[].class);
/**
+ * <p>Dimensions of full pixel array, possibly
+ * including black calibration pixels.</p>
+ * <p>Maximum output resolution for raw format must
+ * match this in
+ * android.scaler.info.availableSizesPerFormat.</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);
+
+ /**
* <p>Gain factor from electrons to raw units when
* ISO=100</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -614,6 +971,18 @@
new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
/**
+ * <p>A fixed black level offset for each of the color filter arrangement
+ * (CFA) mosaic channels.</p>
+ * <p>This tag specifies the zero light value for each of the CFA mosaic
+ * channels in the camera sensor.</p>
+ * <p>The values are given in row-column scan order, with the first value
+ * corresponding to the element of the CFA in row=0, column=0.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<int[]> SENSOR_BLACK_LEVEL_PATTERN =
+ new Key<int[]>("android.sensor.blackLevelPattern", int[].class);
+
+ /**
* <p>Maximum sensitivity that is implemented
* purely through analog gain.</p>
* <p>For {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} values less than or
@@ -642,6 +1011,20 @@
new Key<Integer>("android.sensor.orientation", int.class);
/**
+ * <p>The number of input samples for each dimension of
+ * {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}.</p>
+ * <p>The number of input samples for the hue, saturation, and value
+ * dimension of {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}. The order of the
+ * dimensions given is hue, saturation, value; where hue is the 0th
+ * element.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP
+ */
+ public static final Key<int[]> SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS =
+ new Key<int[]>("android.sensor.profileHueSatMapDimensions", int[].class);
+
+ /**
* <p>Optional. Defaults to [OFF]. Lists the supported test
* pattern modes for android.test.patternMode.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -699,14 +1082,20 @@
new Key<int[]>("android.led.availableLeds", int[].class);
/**
- * <p>The camera 3 HAL device can implement one of two possible
- * operational modes; limited and full. Full support is
- * expected from new higher-end devices. Limited mode has
- * hardware requirements roughly in line with those for a
- * camera HAL device v1 implementation, and is expected from
- * older or inexpensive devices. Full is a strict superset of
- * limited, and they share the same essential operational flow.</p>
- * <p>For full details refer to "S3. Operational Modes" in camera3.h</p>
+ * <p>Generally classifies the overall set of the camera device functionality.</p>
+ * <p>Camera devices will come in two flavors: LIMITED and FULL.</p>
+ * <p>A FULL device has the most support possible and will enable the
+ * widest range of use cases such as:</p>
+ * <ul>
+ * <li>30 FPS at maximum resolution (== sensor resolution)</li>
+ * <li>Per frame control</li>
+ * <li>Manual sensor control</li>
+ * <li>Zero Shutter Lag (ZSL)</li>
+ * </ul>
+ * <p>A LIMITED device may have some or none of the above characteristics.
+ * To find out more refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+ *
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
*/
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index a1f432d..1ce91f6 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -206,6 +206,45 @@
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
//
+ // Enumeration values for CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+ //
+
+ /**
+ * <p>The lens focus distance is not accurate, and the units used for
+ * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.
+ * Setting the lens to the same focus distance on separate occasions may
+ * result in a different real focus distance, depending on factors such
+ * as the orientation of the device, the age of the focusing mechanism,
+ * and the device temperature. The focus distance value will still be
+ * in the range of <code>[0, {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}]</code>, where 0
+ * represents the farthest focus.</p>
+ *
+ * @see CaptureRequest#LENS_FOCUS_DISTANCE
+ * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
+ * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+ */
+ public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0;
+
+ /**
+ * <p>The lens focus distance is measured in diopters. However, setting the lens
+ * to the same focus distance on separate occasions may result in a
+ * different real focus distance, depending on factors such as the
+ * orientation of the device, the age of the focusing mechanism, and
+ * the device temperature.</p>
+ * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+ */
+ public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1;
+
+ /**
+ * <p>The lens focus distance is measured in diopters. The lens mechanism is
+ * calibrated so that setting the same focus distance is repeatable on
+ * multiple occasions with good accuracy, and the focus distance corresponds
+ * to the real physical distance to the plane of best focus.</p>
+ * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+ */
+ public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2;
+
+ //
// Enumeration values for CameraCharacteristics#LENS_FACING
//
@@ -220,6 +259,170 @@
public static final int LENS_FACING_BACK = 1;
//
+ // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ //
+
+ /**
+ * <p>The minimal set of capabilities that every camera
+ * device (regardless of {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel})
+ * will support.</p>
+ * <p>The full set of features supported by this capability makes
+ * the camera2 api backwards compatible with the camera1
+ * (android.hardware.Camera) API.</p>
+ * <p>TODO: @hide this. Doesn't really mean anything except
+ * act as a catch-all for all the 'base' functionality.</p>
+ *
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0;
+
+ /**
+ * <p>This is a catch-all capability to include all other
+ * tags or functionality not encapsulated by one of the other
+ * capabilities.</p>
+ * <p>A typical example is all tags marked 'optional'.</p>
+ * <p>TODO: @hide. We may not need this if we @hide all the optional
+ * tags not belonging to a capability.</p>
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL = 1;
+
+ /**
+ * <p>The camera device can be manually controlled (3A algorithms such
+ * as auto exposure, and auto focus can be
+ * bypassed), this includes but is not limited to:</p>
+ * <ul>
+ * <li>Manual exposure control<ul>
+ * <li>{@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</li>
+ * <li>{@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
+ * </ul>
+ * </li>
+ * <li>Manual sensitivity control<ul>
+ * <li>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</li>
+ * <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
+ * <li>{@link CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR android.sensor.baseGainFactor}</li>
+ * </ul>
+ * </li>
+ * <li>Manual lens control<ul>
+ * <li>android.lens.*</li>
+ * </ul>
+ * </li>
+ * <li>Manual flash control<ul>
+ * <li>android.flash.*</li>
+ * </ul>
+ * </li>
+ * <li>Manual black level locking<ul>
+ * <li>{@link CaptureRequest#BLACK_LEVEL_LOCK android.blackLevel.lock}</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * <p>If any of the above 3A algorithms are enabled, then the camera
+ * device will accurately report the values applied by 3A in the
+ * result.</p>
+ *
+ * @see CaptureRequest#BLACK_LEVEL_LOCK
+ * @see CameraCharacteristics#SENSOR_BASE_GAIN_FACTOR
+ * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+ * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
+ * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
+ * @see CaptureRequest#SENSOR_SENSITIVITY
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2;
+
+ /**
+ * <p>TODO: This should be @hide</p>
+ * <ul>
+ * <li>Manual tonemap control<ul>
+ * <li>{@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}</li>
+ * <li>{@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}</li>
+ * <li>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed}</li>
+ * <li>{@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</li>
+ * <li>{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</li>
+ * </ul>
+ * </li>
+ * <li>Manual white balance control<ul>
+ * <li>{@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}</li>
+ * <li>{@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}</li>
+ * </ul>
+ * </li>
+ * <li>Lens shading map information<ul>
+ * <li>{@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap}</li>
+ * <li>{@link CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE android.lens.info.shadingMapSize}</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * <p>If auto white balance is enabled, then the camera device
+ * will accurately report the values applied by AWB in the result.</p>
+ * <p>The camera device will also support everything in MANUAL_SENSOR
+ * except manual lens control and manual flash control.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+ * @see CameraCharacteristics#LENS_INFO_SHADING_MAP_SIZE
+ * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+ * @see CaptureRequest#TONEMAP_CURVE_BLUE
+ * @see CaptureRequest#TONEMAP_CURVE_GREEN
+ * @see CaptureRequest#TONEMAP_CURVE_RED
+ * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
+ * @see CaptureRequest#TONEMAP_MODE
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_GCAM = 3;
+
+ /**
+ * <p>The camera device supports the Zero Shutter Lag use case.</p>
+ * <ul>
+ * <li>At least one input stream can be used.</li>
+ * <li>RAW_OPAQUE is supported as an output/input format</li>
+ * <li>Using RAW_OPAQUE does not cause a frame rate drop
+ * relative to the sensor's maximum capture rate (at that
+ * resolution).</li>
+ * <li>RAW_OPAQUE will be reprocessable into both YUV_420_888
+ * and JPEG formats.</li>
+ * <li>The maximum available resolution for RAW_OPAQUE streams
+ * (both input/output) will match the maximum available
+ * resolution of JPEG streams.</li>
+ * </ul>
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
+
+ /**
+ * <p>The camera device supports outputting RAW buffers that can be
+ * saved offline into a DNG format. It can reprocess DNG
+ * files (produced from the same camera device) back into YUV.</p>
+ * <ul>
+ * <li>At least one input stream can be used.</li>
+ * <li>RAW16 is supported as output/input format.</li>
+ * <li>RAW16 is reprocessable into both YUV_420_888 and JPEG
+ * formats.</li>
+ * <li>The maximum available resolution for RAW16 streams (both
+ * input/output) will match the value in
+ * android.sensor.info.pixelArraySize.</li>
+ * <li>All DNG-related optional metadata entries are provided
+ * by the camera device.</li>
+ * </ul>
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5;
+
+ //
+ // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ //
+
+ /**
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ */
+ public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0;
+
+ /**
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ */
+ public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1;
+
+ //
// Enumeration values for CameraCharacteristics#LED_AVAILABLE_LEDS
//
@@ -802,6 +1005,14 @@
*/
public static final int CONTROL_MODE_USE_SCENE_MODE = 2;
+ /**
+ * <p>Same as OFF mode, except that this capture will not be
+ * used by camera device background auto-exposure, auto-white balance and
+ * auto-focus algorithms to update their statistics.</p>
+ * @see CaptureRequest#CONTROL_MODE
+ */
+ public static final int CONTROL_MODE_OFF_KEEP_STATE = 3;
+
//
// Enumeration values for CaptureRequest#CONTROL_SCENE_MODE
//
@@ -978,6 +1189,34 @@
public static final int FLASH_MODE_TORCH = 2;
//
+ // Enumeration values for CaptureRequest#HOT_PIXEL_MODE
+ //
+
+ /**
+ * <p>The frame rate must not be reduced relative to sensor raw output
+ * for this option.</p>
+ * <p>No hot pixel correction is applied.</p>
+ * @see CaptureRequest#HOT_PIXEL_MODE
+ */
+ public static final int HOT_PIXEL_MODE_OFF = 0;
+
+ /**
+ * <p>The frame rate must not be reduced relative to sensor raw output
+ * for this option.</p>
+ * <p>Hot pixel correction is applied.</p>
+ * @see CaptureRequest#HOT_PIXEL_MODE
+ */
+ public static final int HOT_PIXEL_MODE_FAST = 1;
+
+ /**
+ * <p>The frame rate may be reduced relative to sensor raw output
+ * for this option.</p>
+ * <p>A high-quality hot pixel correction is applied.</p>
+ * @see CaptureRequest#HOT_PIXEL_MODE
+ */
+ public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2;
+
+ //
// Enumeration values for CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index ee18041..326205e 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -639,10 +639,10 @@
/**
* <p>Whether AWB is currently locked to its
- * latest calculated values</p>
+ * latest calculated values.</p>
* <p>Note that AWB lock is only meaningful for AUTO
* mode; in other modes, AWB is already fixed to a specific
- * setting</p>
+ * setting.</p>
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
@@ -763,11 +763,17 @@
* one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
* as it wishes. The camera device scene mode 3A settings are provided by
* android.control.sceneModeOverrides.</p>
+ * <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
+ * is that this frame will not be used by camera device background 3A statistics
+ * update, as if this frame is never captured. This mode can be used in the scenario
+ * where the application doesn't want a 3A manual control capture to affect
+ * the subsequent auto 3A capture results.</p>
*
* @see CaptureRequest#CONTROL_AF_MODE
* @see #CONTROL_MODE_OFF
* @see #CONTROL_MODE_AUTO
* @see #CONTROL_MODE_USE_SCENE_MODE
+ * @see #CONTROL_MODE_OFF_KEEP_STATE
*/
public static final Key<Integer> CONTROL_MODE =
new Key<Integer>("android.control.mode", int.class);
@@ -866,6 +872,18 @@
new Key<Integer>("android.flash.mode", int.class);
/**
+ * <p>Set operational mode for hot pixel correction.</p>
+ * <p>Hotpixel correction interpolates out, or otherwise removes, pixels
+ * that do not accurately encode the incoming light (i.e. pixels that
+ * are stuck at an arbitrary value).</p>
+ * @see #HOT_PIXEL_MODE_OFF
+ * @see #HOT_PIXEL_MODE_FAST
+ * @see #HOT_PIXEL_MODE_HIGH_QUALITY
+ */
+ public static final Key<Integer> HOT_PIXEL_MODE =
+ new Key<Integer>("android.hotPixel.mode", int.class);
+
+ /**
* <p>GPS coordinates to include in output JPEG
* EXIF</p>
*/
@@ -1123,62 +1141,45 @@
* largest requested stream resolution.</li>
* <li>Using more than one output stream in a request does not affect the
* frame duration.</li>
- * <li>JPEG streams act like processed YUV streams in requests for which
- * they are not included; in requests in which they are directly
- * referenced, they act as JPEG streams. This is because supporting a
- * JPEG stream requires the underlying YUV data to always be ready for
- * use by a JPEG encoder, but the encoder will only be used (and impact
- * frame duration) on requests that actually reference a JPEG stream.</li>
- * <li>The JPEG processor can run concurrently to the rest of the camera
- * pipeline, but cannot process more than 1 capture at a time.</li>
+ * <li>Certain format-streams may need to do additional background processing
+ * before data is consumed/produced by that stream. These processors
+ * can run concurrently to the rest of the camera pipeline, but
+ * cannot process more than 1 capture at a time.</li>
* </ul>
* <p>The necessary information for the application, given the model above,
- * is provided via the android.scaler.available*MinDurations fields.
+ * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
* These are used to determine the maximum frame rate / minimum frame
* duration that is possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
- * determine the minimum frame duration it can request from the HAL
+ * determine the minimum frame duration it can request from the camera
* device:</p>
* <ol>
- * <li>Given the application's currently configured set of output
- * streams, <code>S</code>, divide them into three sets: streams in a JPEG format
- * <code>SJ</code>, streams in a raw sensor format <code>SR</code>, and the rest ('processed')
- * <code>SP</code>.</li>
- * <li>For each subset of streams, find the largest resolution (by pixel
- * count) in the subset. This gives (at most) three resolutions <code>RJ</code>,
- * <code>RR</code>, and <code>RP</code>.</li>
- * <li>If <code>RJ</code> is greater than <code>RP</code>, set <code>RP</code> equal to <code>RJ</code>. If there is
- * no exact match for <code>RP == RJ</code> (in particular there isn't an available
- * processed resolution at the same size as <code>RJ</code>), then set <code>RP</code> equal
- * to the smallest processed resolution that is larger than <code>RJ</code>. If
- * there are no processed resolutions larger than <code>RJ</code>, then set <code>RJ</code> to
- * the processed resolution closest to <code>RJ</code>.</li>
- * <li>If <code>RP</code> is greater than <code>RR</code>, set <code>RR</code> equal to <code>RP</code>. If there is
- * no exact match for <code>RR == RP</code> (in particular there isn't an available
- * raw resolution at the same size as <code>RP</code>), then set <code>RR</code> equal to
- * or to the smallest raw resolution that is larger than <code>RP</code>. If
- * there are no raw resolutions larger than <code>RP</code>, then set <code>RR</code> to
- * the raw resolution closest to <code>RP</code>.</li>
- * <li>Look up the matching minimum frame durations in the property lists
- * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations},
- * android.scaler.availableRawMinDurations, and
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations}. This gives three
- * minimum frame durations <code>FJ</code>, <code>FR</code>, and <code>FP</code>.</li>
- * <li>If a stream of requests do not use a JPEG stream, then the minimum
- * supported frame duration for each request is <code>max(FR, FP)</code>.</li>
- * <li>If a stream of requests all use the JPEG stream, then the minimum
- * supported frame duration for each request is <code>max(FR, FP, FJ)</code>.</li>
- * <li>If a mix of JPEG-using and non-JPEG-using requests is submitted by
- * the application, then the HAL will have to delay JPEG-using requests
- * whenever the JPEG encoder is still busy processing an older capture.
- * This will happen whenever a JPEG-using request starts capture less
- * than <code>FJ</code> <em>ns</em> after a previous JPEG-using request. The minimum
- * supported frame duration will vary between the values calculated in
- * #6 and #7.</li>
+ * <li>Let the set of currently configured input/output streams
+ * be called <code>S</code>.</li>
+ * <li>Find the minimum frame durations for each stream in <code>S</code>, by
+ * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+ * its respective size/format). Let this set of frame durations be called
+ * <code>F</code>.</li>
+ * <li>For any given request <code>R</code>, the minimum frame duration allowed
+ * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
+ * used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
+ * <p>If none of the streams in <code>S_r</code> have a stall time (listed in
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+ * <code>F</code> determines the steady state frame rate that the application will
+ * get if it uses <code>R</code> as a repeating request. Let this special kind
+ * of request be called <code>Rsimple</code>.</p>
+ * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
+ * by a single capture of a new request <code>Rstall</code> (which has at least
+ * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
+ * same minimum frame duration this will not cause a frame rate loss
+ * if all buffers from the previous <code>Rstall</code> have already been
+ * delivered.</p>
+ * <p>For more details about stalling, see
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 160b6fc..f556d71 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -938,11 +938,17 @@
* one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
* as it wishes. The camera device scene mode 3A settings are provided by
* android.control.sceneModeOverrides.</p>
+ * <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
+ * is that this frame will not be used by camera device background 3A statistics
+ * update, as if this frame is never captured. This mode can be used in the scenario
+ * where the application doesn't want a 3A manual control capture to affect
+ * the subsequent auto 3A capture results.</p>
*
* @see CaptureRequest#CONTROL_AF_MODE
* @see #CONTROL_MODE_OFF
* @see #CONTROL_MODE_AUTO
* @see #CONTROL_MODE_USE_SCENE_MODE
+ * @see #CONTROL_MODE_OFF_KEEP_STATE
*/
public static final Key<Integer> CONTROL_MODE =
new Key<Integer>("android.control.mode", int.class);
@@ -1008,6 +1014,31 @@
new Key<Integer>("android.flash.state", int.class);
/**
+ * <p>List of <code>(x, y)</code> coordinates of hot/defective pixels on the
+ * sensor, where <code>(x, y)</code> lies between <code>(0, 0)</code>, which is the top-left
+ * of the pixel array, and the width,height of the pixel array given in
+ * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}. This may include hot pixels
+ * that lie outside of the active array bounds given by
+ * android.sensor.activeArraySize.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
+ */
+ public static final Key<int[]> HOT_PIXEL_MAP =
+ new Key<int[]>("android.hotPixel.map", int[].class);
+
+ /**
+ * <p>Set operational mode for hot pixel correction.</p>
+ * <p>Hotpixel correction interpolates out, or otherwise removes, pixels
+ * that do not accurately encode the incoming light (i.e. pixels that
+ * are stuck at an arbitrary value).</p>
+ * @see #HOT_PIXEL_MODE_OFF
+ * @see #HOT_PIXEL_MODE_FAST
+ * @see #HOT_PIXEL_MODE_HIGH_QUALITY
+ */
+ public static final Key<Integer> HOT_PIXEL_MODE =
+ new Key<Integer>("android.hotPixel.mode", int.class);
+
+ /**
* <p>GPS coordinates to include in output JPEG
* EXIF</p>
*/
@@ -1344,62 +1375,45 @@
* largest requested stream resolution.</li>
* <li>Using more than one output stream in a request does not affect the
* frame duration.</li>
- * <li>JPEG streams act like processed YUV streams in requests for which
- * they are not included; in requests in which they are directly
- * referenced, they act as JPEG streams. This is because supporting a
- * JPEG stream requires the underlying YUV data to always be ready for
- * use by a JPEG encoder, but the encoder will only be used (and impact
- * frame duration) on requests that actually reference a JPEG stream.</li>
- * <li>The JPEG processor can run concurrently to the rest of the camera
- * pipeline, but cannot process more than 1 capture at a time.</li>
+ * <li>Certain format-streams may need to do additional background processing
+ * before data is consumed/produced by that stream. These processors
+ * can run concurrently to the rest of the camera pipeline, but
+ * cannot process more than 1 capture at a time.</li>
* </ul>
* <p>The necessary information for the application, given the model above,
- * is provided via the android.scaler.available*MinDurations fields.
+ * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
* These are used to determine the maximum frame rate / minimum frame
* duration that is possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
- * determine the minimum frame duration it can request from the HAL
+ * determine the minimum frame duration it can request from the camera
* device:</p>
* <ol>
- * <li>Given the application's currently configured set of output
- * streams, <code>S</code>, divide them into three sets: streams in a JPEG format
- * <code>SJ</code>, streams in a raw sensor format <code>SR</code>, and the rest ('processed')
- * <code>SP</code>.</li>
- * <li>For each subset of streams, find the largest resolution (by pixel
- * count) in the subset. This gives (at most) three resolutions <code>RJ</code>,
- * <code>RR</code>, and <code>RP</code>.</li>
- * <li>If <code>RJ</code> is greater than <code>RP</code>, set <code>RP</code> equal to <code>RJ</code>. If there is
- * no exact match for <code>RP == RJ</code> (in particular there isn't an available
- * processed resolution at the same size as <code>RJ</code>), then set <code>RP</code> equal
- * to the smallest processed resolution that is larger than <code>RJ</code>. If
- * there are no processed resolutions larger than <code>RJ</code>, then set <code>RJ</code> to
- * the processed resolution closest to <code>RJ</code>.</li>
- * <li>If <code>RP</code> is greater than <code>RR</code>, set <code>RR</code> equal to <code>RP</code>. If there is
- * no exact match for <code>RR == RP</code> (in particular there isn't an available
- * raw resolution at the same size as <code>RP</code>), then set <code>RR</code> equal to
- * or to the smallest raw resolution that is larger than <code>RP</code>. If
- * there are no raw resolutions larger than <code>RP</code>, then set <code>RR</code> to
- * the raw resolution closest to <code>RP</code>.</li>
- * <li>Look up the matching minimum frame durations in the property lists
- * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations},
- * android.scaler.availableRawMinDurations, and
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations}. This gives three
- * minimum frame durations <code>FJ</code>, <code>FR</code>, and <code>FP</code>.</li>
- * <li>If a stream of requests do not use a JPEG stream, then the minimum
- * supported frame duration for each request is <code>max(FR, FP)</code>.</li>
- * <li>If a stream of requests all use the JPEG stream, then the minimum
- * supported frame duration for each request is <code>max(FR, FP, FJ)</code>.</li>
- * <li>If a mix of JPEG-using and non-JPEG-using requests is submitted by
- * the application, then the HAL will have to delay JPEG-using requests
- * whenever the JPEG encoder is still busy processing an older capture.
- * This will happen whenever a JPEG-using request starts capture less
- * than <code>FJ</code> <em>ns</em> after a previous JPEG-using request. The minimum
- * supported frame duration will vary between the values calculated in
- * #6 and #7.</li>
+ * <li>Let the set of currently configured input/output streams
+ * be called <code>S</code>.</li>
+ * <li>Find the minimum frame durations for each stream in <code>S</code>, by
+ * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+ * its respective size/format). Let this set of frame durations be called
+ * <code>F</code>.</li>
+ * <li>For any given request <code>R</code>, the minimum frame duration allowed
+ * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
+ * used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
+ * <p>If none of the streams in <code>S_r</code> have a stall time (listed in
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+ * <code>F</code> determines the steady state frame rate that the application will
+ * get if it uses <code>R</code> as a repeating request. Let this special kind
+ * of request be called <code>Rsimple</code>.</p>
+ * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
+ * by a single capture of a new request <code>Rstall</code> (which has at least
+ * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
+ * same minimum frame duration this will not cause a frame rate loss
+ * if all buffers from the previous <code>Rstall</code> have already been
+ * delivered.</p>
+ * <p>For more details about stalling, see
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
@@ -1440,6 +1454,83 @@
new Key<Float>("android.sensor.temperature", float.class);
/**
+ * <p>A per-device calibration transform matrix to be applied after the
+ * color space transform when rendering the raw image buffer.</p>
+ * <p>This matrix is expressed as a 3x3 matrix in row-major-order, and
+ * contains a per-device calibration transform that maps colors
+ * from reference camera color space (i.e. the "golden module"
+ * colorspace) into this camera device's linear native sensor color
+ * space for the current scene illumination and white balance choice.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<Rational[]> SENSOR_CALIBRATION_TRANSFORM =
+ new Key<Rational[]>("android.sensor.calibrationTransform", Rational[].class);
+
+ /**
+ * <p>A matrix that transforms color values from CIE XYZ color space to
+ * reference camera color space when rendering the raw image buffer.</p>
+ * <p>This matrix is expressed as a 3x3 matrix in row-major-order, and
+ * contains a color transform matrix that maps colors from the CIE
+ * XYZ color space to the reference camera raw color space (i.e. the
+ * "golden module" colorspace) for the current scene illumination and
+ * white balance choice.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<Rational[]> SENSOR_COLOR_TRANSFORM =
+ new Key<Rational[]>("android.sensor.colorTransform", Rational[].class);
+
+ /**
+ * <p>A matrix that transforms white balanced camera colors to the CIE XYZ
+ * colorspace with a D50 whitepoint.</p>
+ * <p>This matrix is expressed as a 3x3 matrix in row-major-order, and contains
+ * a color transform matrix that maps a unit vector in the linear native
+ * sensor color space to the D50 whitepoint in CIE XYZ color space.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<Rational[]> SENSOR_FORWARD_MATRIX =
+ new Key<Rational[]>("android.sensor.forwardMatrix", Rational[].class);
+
+ /**
+ * <p>The estimated white balance at the time of capture.</p>
+ * <p>The estimated white balance encoded as the RGB values of the
+ * perfectly neutral color point in the linear native sensor color space.
+ * The order of the values is R, G, B; where R is in the lowest index.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<Rational[]> SENSOR_NEUTRAL_COLOR_POINT =
+ new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class);
+
+ /**
+ * <p>A mapping containing a hue shift, saturation scale, and value scale
+ * for each pixel.</p>
+ * <p>hue_samples, saturation_samples, and value_samples are given in
+ * {@link CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS android.sensor.profileHueSatMapDimensions}.</p>
+ * <p>Each entry of this map contains three floats corresponding to the
+ * hue shift, saturation scale, and value scale, respectively; where the
+ * hue shift has the lowest index. The map entries are stored in the tag
+ * in nested loop order, with the value divisions in the outer loop, the
+ * hue divisions in the middle loop, and the saturation divisions in the
+ * inner loop. All zero input saturation entries are required to have a
+ * value scale factor of 1.0.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS
+ */
+ public static final Key<float[]> SENSOR_PROFILE_HUE_SAT_MAP =
+ new Key<float[]>("android.sensor.profileHueSatMap", float[].class);
+
+ /**
+ * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p>
+ * <p>This tag contains a default tone curve that can be applied while
+ * processing the image as a starting point for user adjustments.
+ * The curve is specified as a list of value pairs in linear gamma.
+ * The curve is interpolated using a cubic spline.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<float[]> SENSOR_PROFILE_TONE_CURVE =
+ new Key<float[]>("android.sensor.profileToneCurve", float[].class);
+
+ /**
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4879be6..345ff82 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -551,9 +551,9 @@
public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
public static final int STATE_WIFI_SCAN_FLAG = 1<<29;
public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
+ public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
// These are on the lower bits used for the command; if they change
// we need to write another int of data.
- public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
public static final int STATE_PHONE_SCANNING_FLAG = 1<<23;
public static final int STATE_AUDIO_ON_FLAG = 1<<22;
public static final int STATE_VIDEO_ON_FLAG = 1<<21;
@@ -572,9 +572,26 @@
// The wake lock that was acquired at this point.
public HistoryTag wakelockTag;
- public static final int EVENT_NONE = 0;
- public static final int EVENT_PROC_STARTED = 1;
- public static final int EVENT_PROC_FINISHED = 2;
+ public static final int EVENT_FLAG_START = 0x8000;
+ public static final int EVENT_FLAG_FINISH = 0x4000;
+
+ // No event in this item.
+ public static final int EVENT_NONE = 0x0000;
+ // Event is about a process that is running.
+ public static final int EVENT_PROC = 0x0001;
+ // Event is about an application package that is in the foreground.
+ public static final int EVENT_FOREGROUND = 0x0002;
+ // Event is about an application package that is at the top of the screen.
+ public static final int EVENT_TOP = 0x0003;
+ // Number of event types.
+ public static final int EVENT_COUNT = 0x0004;
+
+ public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START;
+ public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH;
+ public static final int EVENT_FOREGROUND_START = EVENT_FOREGROUND | EVENT_FLAG_START;
+ public static final int EVENT_FOREGROUND_FINISH = EVENT_FOREGROUND | EVENT_FLAG_FINISH;
+ public static final int EVENT_TOP_START = EVENT_TOP | EVENT_FLAG_START;
+ public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH;
// For CMD_EVENT.
public int eventCode;
@@ -942,6 +959,14 @@
SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
};
+ public static final String[] HISTORY_EVENT_NAMES = new String[] {
+ "null", "proc", "fg", "top"
+ };
+
+ public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
+ "Nl", "Pr", "Fg", "Tp"
+ };
+
/**
* Returns the time in microseconds that wifi has been on while the device was
* running on battery.
@@ -2497,6 +2522,9 @@
case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
pw.print(checkin ? "f" : "failure");
break;
+ case BatteryManager.BATTERY_HEALTH_COLD:
+ pw.print(checkin ? "c" : "cold");
+ break;
default:
pw.print(oldHealth);
break;
@@ -2536,25 +2564,23 @@
printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag,
HISTORY_STATE_DESCRIPTIONS, !checkin);
if (rec.eventCode != HistoryItem.EVENT_NONE) {
- switch (rec.eventCode) {
- case HistoryItem.EVENT_PROC_STARTED:
- pw.print(checkin ? ",PrSt=" : " procstart=");
- break;
- case HistoryItem.EVENT_PROC_FINISHED:
- pw.print(checkin ? ",PrFn=" : " procfin=");
- break;
- default:
- if (checkin) {
- pw.print(",?cmd_");
- pw.print(rec.eventCode);
- pw.print("=");
- } else {
- pw.print(" cmd_");
- pw.print(rec.eventCode);
- pw.print("=");
- }
- break;
+ pw.print(checkin ? "," : " ");
+ if ((rec.eventCode&HistoryItem.EVENT_FLAG_START) != 0) {
+ pw.print("+");
+ } else if ((rec.eventCode&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+ pw.print("-");
}
+ String[] eventNames = checkin ? HISTORY_EVENT_CHECKIN_NAMES
+ : HISTORY_EVENT_NAMES;
+ int idx = rec.eventCode & ~(HistoryItem.EVENT_FLAG_START
+ | HistoryItem.EVENT_FLAG_FINISH);
+ if (idx >= 0 && idx < eventNames.length) {
+ pw.print(eventNames[idx]);
+ } else {
+ pw.print(checkin ? "Ev" : "event");
+ pw.print(idx);
+ }
+ pw.print("=");
if (checkin) {
pw.print(rec.eventTag.poolIdx);
} else {
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 15a154a..dc18dee 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -326,14 +326,15 @@
*
* @param minCount Always keep at least this many files.
* @param minAge Always keep files younger than this age.
+ * @return if any files were deleted.
*/
- public static void deleteOlderFiles(File dir, int minCount, long minAge) {
+ public static boolean deleteOlderFiles(File dir, int minCount, long minAge) {
if (minCount < 0 || minAge < 0) {
throw new IllegalArgumentException("Constraints must be positive or 0");
}
final File[] files = dir.listFiles();
- if (files == null) return;
+ if (files == null) return false;
// Sort with newest files first
Arrays.sort(files, new Comparator<File>() {
@@ -344,16 +345,20 @@
});
// Keep at least minCount files
+ boolean deleted = false;
for (int i = minCount; i < files.length; i++) {
final File file = files[i];
// Keep files newer than minAge
final long age = System.currentTimeMillis() - file.lastModified();
if (age > minAge) {
- Log.d(TAG, "Deleting old file " + file);
- file.delete();
+ if (file.delete()) {
+ Log.d(TAG, "Deleted old file " + file);
+ deleted = true;
+ }
}
}
+ return deleted;
}
/**
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 905dcb0..f59ef0f6d 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -115,6 +115,13 @@
}
}
+ /** @hide */
+ public void removeAt(int index) {
+ System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+ System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
+ mSize--;
+ }
+
/**
* Adds a mapping from the specified key to the specified value,
* replacing the previous mapping from the specified key if there
@@ -191,6 +198,11 @@
return mValues[index];
}
+ /** @hide */
+ public void setValueAt(int index, boolean value) {
+ mValues[index] = value;
+ }
+
/**
* Returns the index for which {@link #keyAt} would return the
* specified key, or a negative number if the specified
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 8b63359..9aecbea 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -431,7 +431,19 @@
}
/**
- * Sets the outline, defining the shape that casts a shadow.
+ * Sets whether the display list is a projection receiver - that its parent
+ * DisplayList should draw any descendent DisplayLists with
+ * ProjectBackwards=true directly on top of it. Default value is false.
+ */
+ public void setProjectionReceiver(boolean shouldRecieve) {
+ if (hasNativeDisplayList()) {
+ nSetProjectionReceiver(mFinalizer.mNativeDisplayList, shouldRecieve);
+ }
+ }
+
+ /**
+ * Sets the outline, defining the shape that casts a shadow, and the path to
+ * be clipped if setClipToOutline is set.
*
* Deep copies the native path to simplify reference ownership.
*
@@ -445,6 +457,40 @@
}
/**
+ * Enables or disables clipping to the outline.
+ *
+ * @param clipToOutline true if clipping to the outline.
+ */
+ public void setClipToOutline(boolean clipToOutline) {
+ if (hasNativeDisplayList()) {
+ nSetClipToOutline(mFinalizer.mNativeDisplayList, clipToOutline);
+ }
+ }
+
+ /**
+ * Set whether the DisplayList should cast a shadow.
+ *
+ * The shape of the shadow casting area is defined by the outline of the display list, if set
+ * and non-empty, otherwise it will be the bounds rect.
+ */
+ public void setCastsShadow(boolean castsShadow) {
+ if (hasNativeDisplayList()) {
+ nSetCastsShadow(mFinalizer.mNativeDisplayList, castsShadow);
+ }
+ }
+
+ /**
+ * Sets whether the DisplayList should be drawn with perspective applied from the global camera.
+ *
+ * If set to true, camera distance will be ignored. Defaults to false.
+ */
+ public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+ if (hasNativeDisplayList()) {
+ nSetSharesGlobalCamera(mFinalizer.mNativeDisplayList, sharesGlobalCamera);
+ }
+ }
+
+ /**
* Set the static matrix on the display list. The specified matrix is combined with other
* transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
*
@@ -1065,8 +1111,12 @@
private static native void nSetCaching(long displayList, boolean caching);
private static native void nSetClipToBounds(long displayList, boolean clipToBounds);
private static native void nSetProjectBackwards(long displayList, boolean shouldProject);
+ private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve);
private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume);
private static native void nSetOutline(long displayList, long nativePath);
+ private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
+ private static native void nSetCastsShadow(long displayList, boolean castsShadow);
+ private static native void nSetSharesGlobalCamera(long displayList, boolean sharesGlobalCamera);
private static native void nSetAlpha(long displayList, float alpha);
private static native void nSetHasOverlappingRendering(long displayList,
boolean hasOverlappingRendering);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 3384359..b763888 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -46,7 +46,6 @@
private static final int MODIFIER_NONE = 0;
private static final int MODIFIER_SHADOW = 1;
private static final int MODIFIER_SHADER = 2;
- private static final int MODIFIER_COLOR_FILTER = 4;
private final boolean mOpaque;
private long mRenderer;
@@ -284,18 +283,6 @@
private static native int nGetStencilSize();
- void setCountOverdrawEnabled(boolean enabled) {
- nSetCountOverdrawEnabled(mRenderer, enabled);
- }
-
- static native void nSetCountOverdrawEnabled(long renderer, boolean enabled);
-
- float getOverdraw() {
- return nGetOverdraw(mRenderer);
- }
-
- static native float nGetOverdraw(long renderer);
-
///////////////////////////////////////////////////////////////////////////
// Functor
///////////////////////////////////////////////////////////////////////////
@@ -639,15 +626,8 @@
return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
}
- int count;
- int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- count = nSaveLayer(mRenderer, nativePaint, saveFlags);
- } finally {
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
- }
- return count;
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ return nSaveLayer(mRenderer, nativePaint, saveFlags);
}
private static native int nSaveLayer(long renderer, long paint, int saveFlags);
@@ -656,15 +636,8 @@
public int saveLayer(float left, float top, float right, float bottom, Paint paint,
int saveFlags) {
if (left < right && top < bottom) {
- int count;
- int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
- } finally {
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
- }
- return count;
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
}
return save(saveFlags);
}
@@ -746,7 +719,7 @@
@Override
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
startAngle, sweepAngle, useCenter, paint.mNativePaint);
@@ -769,14 +742,9 @@
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing patches
- int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- } finally {
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
- }
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@Override
@@ -784,14 +752,9 @@
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
// Shaders are ignored when drawing patches
- int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- } finally {
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
- }
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
private static native void nDrawPatch(long renderer, long bitmap, byte[] buffer, long chunk,
@@ -912,14 +875,9 @@
}
// Shaders are ignored when drawing bitmaps
- int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, colors, offset, stride, x, y,
- width, height, hasAlpha, nativePaint);
- } finally {
- if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
- }
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmap(mRenderer, colors, offset, stride, x, y,
+ width, height, hasAlpha, nativePaint);
}
private static native void nDrawBitmap(long renderer, int[] colors, int offset, int stride,
@@ -967,7 +925,7 @@
@Override
public void drawCircle(float cx, float cy, float radius, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
} finally {
@@ -1007,7 +965,7 @@
if ((offset | count) < 0 || offset + count > pts.length) {
throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
}
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
} finally {
@@ -1025,7 +983,7 @@
@Override
public void drawOval(RectF oval, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
} finally {
@@ -1045,7 +1003,7 @@
@Override
public void drawPath(Path path, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
if (path.isSimplePath) {
if (path.rects != null) {
@@ -1063,7 +1021,7 @@
private static native void nDrawRects(long renderer, long region, long paint);
void drawRects(float[] rects, int count, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawRects(mRenderer, rects, count, paint.mNativePaint);
} finally {
@@ -1130,7 +1088,7 @@
public void drawPoints(float[] pts, int offset, int count, Paint paint) {
if (count < 2) return;
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
} finally {
@@ -1180,7 +1138,7 @@
@Override
public void drawRect(float left, float top, float right, float bottom, Paint paint) {
if (left == right || top == bottom) return;
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
} finally {
@@ -1208,7 +1166,7 @@
@Override
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
+ int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
rx, ry, paint.mNativePaint);
@@ -1388,12 +1346,6 @@
private int setupModifiers(Bitmap b, Paint paint) {
if (b.getConfig() != Bitmap.Config.ALPHA_8) {
- final ColorFilter filter = paint.getColorFilter();
- if (filter != null) {
- nSetupColorFilter(mRenderer, filter.nativeColorFilter);
- return MODIFIER_COLOR_FILTER;
- }
-
return MODIFIER_NONE;
} else {
return setupModifiers(paint);
@@ -1415,12 +1367,6 @@
modifiers |= MODIFIER_SHADER;
}
- final ColorFilter filter = paint.getColorFilter();
- if (filter != null) {
- nSetupColorFilter(mRenderer, filter.nativeColorFilter);
- modifiers |= MODIFIER_COLOR_FILTER;
- }
-
return modifiers;
}
@@ -1439,26 +1385,10 @@
modifiers |= MODIFIER_SHADER;
}
- final ColorFilter filter = paint.getColorFilter();
- if (filter != null && (flags & MODIFIER_COLOR_FILTER) != 0) {
- nSetupColorFilter(mRenderer, filter.nativeColorFilter);
- modifiers |= MODIFIER_COLOR_FILTER;
- }
-
return modifiers;
}
- private int setupColorFilter(Paint paint) {
- final ColorFilter filter = paint.getColorFilter();
- if (filter != null) {
- nSetupColorFilter(mRenderer, filter.nativeColorFilter);
- return MODIFIER_COLOR_FILTER;
- }
- return MODIFIER_NONE;
- }
-
private static native void nSetupShader(long renderer, long shader);
- private static native void nSetupColorFilter(long renderer, long colorFilter);
private static native void nSetupShadow(long renderer, float radius,
float dx, float dy, int color);
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 37154eb..1d30824 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -48,7 +48,7 @@
if (paint != null) {
GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint);
GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ?
- paint.getColorFilter().nativeColorFilter : 0);
+ paint.getColorFilter().native_instance : 0);
}
}
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 449bad6..5002fe5 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -109,9 +109,7 @@
private static final String[] OVERDRAW = {
OVERDRAW_PROPERTY_SHOW,
- OVERDRAW_PROPERTY_COUNT
};
- private static final int OVERDRAW_TYPE_COUNT = 1;
private static final int GL_VERSION = 2;
static EGL10 sEgl;
@@ -160,8 +158,6 @@
boolean mDebugDirtyRegions;
int mDebugOverdraw = -1;
- HardwareLayer mDebugOverdrawLayer;
- Paint mDebugOverdrawPaint;
final boolean mTranslucent;
@@ -495,14 +491,6 @@
return new GLES20RenderLayer(width, height, isOpaque);
}
- void countOverdraw(HardwareCanvas canvas) {
- ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
- }
-
- float getOverdraw(HardwareCanvas canvas) {
- return ((GLES20Canvas) canvas).getOverdraw();
- }
-
@Override
public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
return ((GLES20TextureLayer) layer).getSurfaceTexture();
@@ -706,14 +694,6 @@
if (debugOverdraw != mDebugOverdraw) {
changed = true;
mDebugOverdraw = debugOverdraw;
-
- if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
- if (mDebugOverdrawLayer != null) {
- mDebugOverdrawLayer.destroy();
- mDebugOverdrawLayer = null;
- mDebugOverdrawPaint = null;
- }
- }
}
if (loadProperties()) {
@@ -1182,7 +1162,6 @@
if (mDrawDelta > 0) {
mFrameCount++;
- debugOverdraw(attachInfo, dirty, canvas, displayList);
debugDirtyRegions(dirty, canvas);
drawProfileData(attachInfo);
}
@@ -1201,55 +1180,6 @@
}
}
- private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
- HardwareCanvas canvas, DisplayList displayList) {
-
- if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
- if (mDebugOverdrawLayer == null) {
- mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
- } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
- mDebugOverdrawLayer.getHeight() != mHeight) {
- mDebugOverdrawLayer.resize(mWidth, mHeight);
- }
-
- if (!mDebugOverdrawLayer.isValid()) {
- mDebugOverdraw = -1;
- return;
- }
-
- HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
- countOverdraw(layerCanvas);
- final int restoreCount = layerCanvas.save();
- layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
- layerCanvas.restoreToCount(restoreCount);
- mDebugOverdrawLayer.end(canvas);
-
- float overdraw = getOverdraw(layerCanvas);
- DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
-
- drawOverdrawCounter(canvas, overdraw, metrics.density);
- }
- }
-
- private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
- final String text = String.format("%.2fx", overdraw);
- final Paint paint = setupPaint(density);
- // HSBtoColor will clamp the values in the 0..1 range
- paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
-
- canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
- }
-
- private Paint setupPaint(float density) {
- if (mDebugOverdrawPaint == null) {
- mDebugOverdrawPaint = new Paint();
- mDebugOverdrawPaint.setAntiAlias(true);
- mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
- mDebugOverdrawPaint.setTextSize(density * 20.0f);
- }
- return mDebugOverdrawPaint;
- }
-
private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
if (mDrawDelta <= 0) {
return view.mDisplayList;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 2013494..352ab83 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -153,14 +153,6 @@
public static final String OVERDRAW_PROPERTY_SHOW = "show";
/**
- * Value for {@link #DEBUG_OVERDRAW_PROPERTY}. When the property is set to this
- * value, an overdraw counter will be shown on screen.
- *
- * @hide
- */
- public static final String OVERDRAW_PROPERTY_COUNT = "count";
-
- /**
* Turn on to debug non-rectangular clip operations.
*
* Possible values:
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2710fdf..fbeddc8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2335,7 +2335,6 @@
* 1 PFLAG3_IS_LAID_OUT
* 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
* 1 PFLAG3_CALLED_SUPER
- * 1 PFLAG3_PROJECT_BACKGROUND
* |-------|-------|-------|-------|
*/
@@ -2372,10 +2371,30 @@
static final int PFLAG3_CALLED_SUPER = 0x10;
/**
- * Flag indicating that the background of this view will be drawn into a
- * display list and projected onto the closest parent projection surface.
+ * Flag indicating that an view will be clipped to its outline.
*/
- static final int PFLAG3_PROJECT_BACKGROUND = 0x20;
+ static final int PFLAG3_CLIP_TO_OUTLINE = 0x20;
+
+ /**
+ * Flag indicating that we're in the process of applying window insets.
+ */
+ static final int PFLAG3_APPLYING_INSETS = 0x40;
+
+ /**
+ * Flag indicating that we're in the process of fitting system windows using the old method.
+ */
+ static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
+
+ /**
+ * Flag indicating that an view will cast a shadow onto the Z=0 plane if elevated.
+ */
+ static final int PFLAG3_CASTS_SHADOW = 0x100;
+
+ /**
+ * Flag indicating that view will be transformed by the global camera if rotated in 3d, or given
+ * a non-0 Z translation.
+ */
+ static final int PFLAG3_SHARES_GLOBAL_CAMERA = 0x200;
/* End of masks for mPrivateFlags3 */
@@ -3304,6 +3323,8 @@
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+
+ OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
}
ListenerInfo mListenerInfo;
@@ -3322,7 +3343,8 @@
private int[] mDrawableState = null;
/**
- * Stores the outline of the view, passed down to the DisplayList level for shadow shape.
+ * Stores the outline of the view, passed down to the DisplayList level for
+ * defining shadow shape and clipping.
*/
private Path mOutline;
@@ -6123,10 +6145,33 @@
* @return {@code true} if this view applied the insets and it should not
* continue propagating further down the hierarchy, {@code false} otherwise.
* @see #getFitsSystemWindows()
- * @see #setFitsSystemWindows(boolean)
+ * @see #setFitsSystemWindows(boolean)
* @see #setSystemUiVisibility(int)
+ *
+ * @deprecated As of API XX use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
+ * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use
+ * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)}
+ * to implement handling their own insets.
*/
protected boolean fitSystemWindows(Rect insets) {
+ if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
+ // If we're not in the process of dispatching the newer apply insets call,
+ // that means we're not in the compatibility path. Dispatch into the newer
+ // apply insets path and take things from there.
+ try {
+ mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
+ return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+ } finally {
+ mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
+ }
+ } else {
+ // We're being called from the newer apply insets path.
+ // Perform the standard fallback behavior.
+ return fitSystemWindowsInt(insets);
+ }
+ }
+
+ private boolean fitSystemWindowsInt(Rect insets) {
if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
@@ -6146,6 +6191,97 @@
}
/**
+ * Called when the view should apply {@link WindowInsets} according to its internal policy.
+ *
+ * <p>This method should be overridden by views that wish to apply a policy different from or
+ * in addition to the default behavior. Clients that wish to force a view subtree
+ * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p>
+ *
+ * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set
+ * it will be called during dispatch instead of this method. The listener may optionally
+ * call this method from its own implementation if it wishes to apply the view's default
+ * insets policy in addition to its own.</p>
+ *
+ * <p>Implementations of this method should either return the insets parameter unchanged
+ * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed
+ * that this view applied itself. This allows new inset types added in future platform
+ * versions to pass through existing implementations unchanged without being erroneously
+ * consumed.</p>
+ *
+ * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows}
+ * property is set then the view will consume the system window insets and apply them
+ * as padding for the view.</p>
+ *
+ * @param insets Insets to apply
+ * @return The supplied insets with any applied insets consumed
+ */
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
+ // We weren't called from within a direct call to fitSystemWindows,
+ // call into it as a fallback in case we're in a class that overrides it
+ // and has logic to perform.
+ if (fitSystemWindows(insets.getSystemWindowInsets())) {
+ return insets.cloneWithSystemWindowInsetsConsumed();
+ }
+ } else {
+ // We were called from within a direct call to fitSystemWindows.
+ if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+ return insets.cloneWithSystemWindowInsetsConsumed();
+ }
+ }
+ return insets;
+ }
+
+ /**
+ * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
+ * window insets to this view. The listener's
+ * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+ * method will be called instead of the view's
+ * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+ *
+ * @param listener Listener to set
+ *
+ * @see #onApplyWindowInsets(WindowInsets)
+ */
+ public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) {
+ getListenerInfo().mOnApplyWindowInsetsListener = listener;
+ }
+
+ /**
+ * Request to apply the given window insets to this view or another view in its subtree.
+ *
+ * <p>This method should be called by clients wishing to apply insets corresponding to areas
+ * obscured by window decorations or overlays. This can include the status and navigation bars,
+ * action bars, input methods and more. New inset categories may be added in the future.
+ * The method returns the insets provided minus any that were applied by this view or its
+ * children.</p>
+ *
+ * <p>Clients wishing to provide custom behavior should override the
+ * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a
+ * {@link OnApplyWindowInsetsListener} via the
+ * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener}
+ * method.</p>
+ *
+ * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method.
+ * </p>
+ *
+ * @param insets Insets to apply
+ * @return The provided insets minus the insets that were consumed
+ */
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ try {
+ mPrivateFlags3 |= PFLAG3_APPLYING_INSETS;
+ if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+ return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets);
+ } else {
+ return onApplyWindowInsets(insets);
+ }
+ } finally {
+ mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS;
+ }
+ }
+
+ /**
* @hide Compute the insets that should be consumed by this view and the ones
* that should propagate to those under it.
*/
@@ -6217,6 +6353,7 @@
/**
* Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed.
+ * @deprecated Use {@link #requestApplyInsets()} for newer platform versions.
*/
public void requestFitSystemWindows() {
if (mParent != null) {
@@ -6225,6 +6362,13 @@
}
/**
+ * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed.
+ */
+ public void requestApplyInsets() {
+ requestFitSystemWindows();
+ }
+
+ /**
* For use by PhoneWindow to make its own system window fitting optional.
* @hide
*/
@@ -10693,6 +10837,78 @@
}
/**
+ * @hide
+ */
+ public final boolean getClipToOutline() {
+ return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
+ }
+
+ /**
+ * @hide
+ */
+ public void setClipToOutline(boolean clipToOutline) {
+ // TODO : Add a fast invalidation here.
+ if (getClipToOutline() != clipToOutline) {
+ if (clipToOutline) {
+ mPrivateFlags3 |= PFLAG3_CLIP_TO_OUTLINE;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
+ }
+ if (mDisplayList != null) {
+ mDisplayList.setClipToOutline(clipToOutline);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public final boolean getCastsShadow() {
+ return ((mPrivateFlags3 & PFLAG3_CASTS_SHADOW) != 0);
+ }
+
+ /**
+ * @hide
+ */
+ public void setCastsShadow(boolean castsShadow) {
+ // TODO : Add a fast invalidation here.
+ if (getCastsShadow() != castsShadow) {
+ if (castsShadow) {
+ mPrivateFlags3 |= PFLAG3_CASTS_SHADOW;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_CASTS_SHADOW;
+ }
+ if (mDisplayList != null) {
+ mDisplayList.setCastsShadow(castsShadow);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public final boolean getSharesGlobalCamera() {
+ return ((mPrivateFlags3 & PFLAG3_SHARES_GLOBAL_CAMERA) != 0);
+ }
+
+ /**
+ * @hide
+ */
+ public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+ // TODO : Add a fast invalidation here.
+ if (getSharesGlobalCamera() != sharesGlobalCamera) {
+ if (sharesGlobalCamera) {
+ mPrivateFlags3 |= PFLAG3_SHARES_GLOBAL_CAMERA;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_SHARES_GLOBAL_CAMERA;
+ }
+ if (mDisplayList != null) {
+ mDisplayList.setSharesGlobalCamera(sharesGlobalCamera);
+ }
+ }
+ }
+
+ /**
* Hit rectangle in parent's coordinates
*
* @param outRect The hit rectangle of the view.
@@ -14344,6 +14560,9 @@
(((ViewGroup) this).mGroupFlags & ViewGroup.FLAG_ISOLATED_Z_VOLUME) != 0);
}
displayList.setOutline(mOutline);
+ displayList.setClipToOutline(getClipToOutline());
+ displayList.setCastsShadow(getCastsShadow());
+ displayList.setSharesGlobalCamera(getSharesGlobalCamera());
float alpha = 1;
if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -15014,6 +15233,7 @@
// Set up drawable properties that are view-independent.
displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
displayList.setProjectBackwards(drawable.isProjected());
+ displayList.setProjectionReceiver(true);
displayList.setClipToBounds(false);
return displayList;
}
@@ -19104,6 +19324,31 @@
public void onViewDetachedFromWindow(View v);
}
+ /**
+ * Listener for applying window insets on a view in a custom way.
+ *
+ * <p>Apps may choose to implement this interface if they want to apply custom policy
+ * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener
+ * is set, its
+ * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+ * method will be called instead of the View's own
+ * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener
+ * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply
+ * the View's normal behavior as part of its own.</p>
+ */
+ public interface OnApplyWindowInsetsListener {
+ /**
+ * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set}
+ * on a View, this listener method will be called instead of the view's own
+ * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+ *
+ * @param v The view applying window insets
+ * @param insets The insets to apply
+ * @return The insets supplied, minus any insets that were consumed
+ */
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
+ }
+
private final class UnsetPressedState implements Runnable {
public void run() {
setPressed(false);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 73b108f..c3bf533 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3178,7 +3178,7 @@
* inherited Z ordering volume.
*/
public void setIsolatedZVolume(boolean isolateZVolume) {
- boolean previousValue = (mGroupFlags & FLAG_ISOLATED_Z_VOLUME) == FLAG_ISOLATED_Z_VOLUME;
+ boolean previousValue = (mGroupFlags & FLAG_ISOLATED_Z_VOLUME) != 0;
if (isolateZVolume != previousValue) {
setBooleanFlag(FLAG_ISOLATED_Z_VOLUME, isolateZVolume);
if (mDisplayList != null) {
@@ -5514,21 +5514,19 @@
}
}
-
@Override
- protected boolean fitSystemWindows(Rect insets) {
- boolean done = super.fitSystemWindows(insets);
- if (!done) {
- final int count = mChildrenCount;
- final View[] children = mChildren;
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ insets = super.dispatchApplyWindowInsets(insets);
+ if (insets.hasInsets()) {
+ final int count = getChildCount();
for (int i = 0; i < count; i++) {
- done = children[i].fitSystemWindows(insets);
- if (done) {
+ insets = getChildAt(i).dispatchApplyWindowInsets(insets);
+ if (!insets.hasInsets()) {
break;
}
}
}
- return done;
+ return insets;
}
/**
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
new file mode 100644
index 0000000..cdfcb43
--- /dev/null
+++ b/core/java/android/view/WindowInsets.java
@@ -0,0 +1,278 @@
+/*
+ * 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.view;
+
+import android.graphics.Rect;
+
+/**
+ * Describes a set of insets for window content.
+ *
+ * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
+ * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
+ * with the adjusted properties.</p>
+ *
+ * @see View.OnApplyWindowInsetsListener
+ * @see View#onApplyWindowInsets(WindowInsets)
+ */
+public class WindowInsets {
+ private Rect mSystemWindowInsets;
+ private Rect mWindowDecorInsets;
+ private Rect mTempRect;
+
+ private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
+
+ /**
+ * Since new insets may be added in the future that existing apps couldn't
+ * know about, this fully empty constant shouldn't be made available to apps
+ * since it would allow them to inadvertently consume unknown insets by returning it.
+ * @hide
+ */
+ public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
+ mSystemWindowInsets = systemWindowInsets;
+ mWindowDecorInsets = windowDecorInsets;
+ }
+
+ /**
+ * Construct a new WindowInsets, copying all values from a source WindowInsets.
+ *
+ * @param src Source to copy insets from
+ */
+ public WindowInsets(WindowInsets src) {
+ mSystemWindowInsets = src.mSystemWindowInsets;
+ mWindowDecorInsets = src.mWindowDecorInsets;
+ }
+
+ /** @hide */
+ public WindowInsets(Rect systemWindowInsets) {
+ mSystemWindowInsets = systemWindowInsets;
+ mWindowDecorInsets = EMPTY_RECT;
+ }
+
+ /**
+ * Used to provide a safe copy of the system window insets to pass through
+ * to the existing fitSystemWindows method and other similar internals.
+ * @hide
+ */
+ public Rect getSystemWindowInsets() {
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+ mTempRect.set(mSystemWindowInsets);
+ return mTempRect;
+ }
+
+ /**
+ * Returns the left system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The left system window inset
+ */
+ public int getSystemWindowInsetLeft() {
+ return mSystemWindowInsets.left;
+ }
+
+ /**
+ * Returns the top system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The top system window inset
+ */
+ public int getSystemWindowInsetTop() {
+ return mSystemWindowInsets.top;
+ }
+
+ /**
+ * Returns the right system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The right system window inset
+ */
+ public int getSystemWindowInsetRight() {
+ return mSystemWindowInsets.right;
+ }
+
+ /**
+ * Returns the bottom system window inset in pixels.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return The bottom system window inset
+ */
+ public int getSystemWindowInsetBottom() {
+ return mSystemWindowInsets.bottom;
+ }
+
+ /**
+ * Returns the left window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The left window decor inset
+ */
+ public int getWindowDecorInsetLeft() {
+ return mWindowDecorInsets.left;
+ }
+
+ /**
+ * Returns the top window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The top window decor inset
+ */
+ public int getWindowDecorInsetTop() {
+ return mWindowDecorInsets.top;
+ }
+
+ /**
+ * Returns the right window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The right window decor inset
+ */
+ public int getWindowDecorInsetRight() {
+ return mWindowDecorInsets.right;
+ }
+
+ /**
+ * Returns the bottom window decor inset in pixels.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return The bottom window decor inset
+ */
+ public int getWindowDecorInsetBottom() {
+ return mWindowDecorInsets.bottom;
+ }
+
+ /**
+ * Returns true if this WindowInsets has nonzero system window insets.
+ *
+ * <p>The system window inset represents the area of a full-screen window that is
+ * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+ * </p>
+ *
+ * @return true if any of the system window inset values are nonzero
+ */
+ public boolean hasSystemWindowInsets() {
+ return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 ||
+ mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0;
+ }
+
+ /**
+ * Returns true if this WindowInsets has nonzero window decor insets.
+ *
+ * <p>The window decor inset represents the area of the window content area that is
+ * partially or fully obscured by decorations within the window provided by the framework.
+ * This can include action bars, title bars, toolbars, etc.</p>
+ *
+ * @return true if any of the window decor inset values are nonzero
+ */
+ public boolean hasWindowDecorInsets() {
+ return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
+ mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0;
+ }
+
+ /**
+ * Returns true if this WindowInsets has any nonzero insets.
+ *
+ * @return true if any inset values are nonzero
+ */
+ public boolean hasInsets() {
+ return hasSystemWindowInsets() || hasWindowDecorInsets();
+ }
+
+ public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+ return result;
+ }
+
+ public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+ boolean right, boolean bottom) {
+ if (left || top || right || bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+ top ? 0 : mSystemWindowInsets.top,
+ right ? 0 : mSystemWindowInsets.right,
+ bottom ? 0 : mSystemWindowInsets.bottom);
+ return result;
+ }
+ return this;
+ }
+
+ public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+ return result;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets.set(0, 0, 0, 0);
+ return result;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+ boolean right, boolean bottom) {
+ if (left || top || right || bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
+ top ? 0 : mWindowDecorInsets.top,
+ right ? 0 : mWindowDecorInsets.right,
+ bottom ? 0 : mWindowDecorInsets.bottom);
+ return result;
+ }
+ return this;
+ }
+
+ public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+ final WindowInsets result = new WindowInsets(this);
+ result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets + " windowDecorInsets=" +
+ mWindowDecorInsets + "}";
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index e7e8006f..c22a5e9 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -54,7 +54,7 @@
*/
public class BatteryStatsHelper {
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final String TAG = BatteryStatsHelper.class.getSimpleName();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 21d2e52..82dcbdb 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -45,6 +45,7 @@
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
@@ -77,7 +78,7 @@
*/
public final class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final boolean DEBUG_HISTORY = false;
private static final boolean USE_OLD_HISTORY = false; // for debugging.
@@ -87,7 +88,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 77 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 79 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -178,6 +179,9 @@
boolean mShuttingDown;
+ HashMap<String, SparseBooleanArray>[] mActiveEvents
+ = (HashMap<String, SparseBooleanArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+
long mHistoryBaseTime;
boolean mHaveBatteryLevel = false;
boolean mRecordingHistory = true;
@@ -1521,15 +1525,25 @@
static final int DELTA_TIME_INT = 0xffffe; // The delta is a following int
static final int DELTA_TIME_ABS = 0xffffd; // Following is an entire abs update.
// Flag in delta int: a new battery level int follows.
- static final int DELTA_BATTERY_LEVEL_FLAG = 0x00400000;
+ static final int DELTA_BATTERY_LEVEL_FLAG = 0x00100000;
// Flag in delta int: a new full state and battery status int follows.
- static final int DELTA_STATE_FLAG = 0x00800000;
+ static final int DELTA_STATE_FLAG = 0x00200000;
// Flag in delta int: contains a wakelock tag.
- static final int DELTA_WAKELOCK_FLAG = 0x01000000;
+ static final int DELTA_WAKELOCK_FLAG = 0x00400000;
// Flag in delta int: contains an event description.
- static final int DELTA_EVENT_FLAG = 0x02000000;
+ static final int DELTA_EVENT_FLAG = 0x00800000;
// These upper bits are the frequently changing state bits.
- static final int DELTA_STATE_MASK = 0xfc000000;
+ static final int DELTA_STATE_MASK = 0xff000000;
+
+ // These are the pieces of battery state that are packed in to the upper bits of
+ // the state int that have been packed in to the first delta int. They must fit
+ // in DELTA_STATE_MASK.
+ static final int STATE_BATTERY_STATUS_MASK = 0x00000007;
+ static final int STATE_BATTERY_STATUS_SHIFT = 29;
+ static final int STATE_BATTERY_HEALTH_MASK = 0x00000007;
+ static final int STATE_BATTERY_HEALTH_SHIFT = 26;
+ static final int STATE_BATTERY_PLUG_MASK = 0x00000003;
+ static final int STATE_BATTERY_PLUG_SHIFT = 24;
public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
@@ -1620,9 +1634,17 @@
}
private int buildStateInt(HistoryItem h) {
- return ((((int)h.batteryStatus)<<28)&0xf0000000)
- | ((((int)h.batteryHealth)<<24)&0x0f000000)
- | ((((int)h.batteryPlugType)<<22)&0x00c00000)
+ int plugType = 0;
+ if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_AC) != 0) {
+ plugType = 1;
+ } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_USB) != 0) {
+ plugType = 2;
+ } else if ((h.batteryPlugType&BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0) {
+ plugType = 3;
+ }
+ return ((h.batteryStatus&STATE_BATTERY_STATUS_MASK)<<STATE_BATTERY_STATUS_SHIFT)
+ | ((h.batteryHealth&STATE_BATTERY_HEALTH_MASK)<<STATE_BATTERY_HEALTH_SHIFT)
+ | ((plugType&STATE_BATTERY_PLUG_MASK)<<STATE_BATTERY_PLUG_SHIFT)
| (h.states&(~DELTA_STATE_MASK));
}
@@ -1670,9 +1692,23 @@
if ((firstToken&DELTA_STATE_FLAG) != 0) {
int stateInt = src.readInt();
cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~DELTA_STATE_MASK));
- cur.batteryStatus = (byte)((stateInt>>28)&0xf);
- cur.batteryHealth = (byte)((stateInt>>24)&0xf);
- cur.batteryPlugType = (byte)((stateInt>>22)&0x3);
+ cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
+ & STATE_BATTERY_STATUS_MASK);
+ cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
+ & STATE_BATTERY_HEALTH_MASK);
+ cur.batteryPlugType = (byte)((stateInt>>STATE_BATTERY_PLUG_SHIFT)
+ & STATE_BATTERY_PLUG_MASK);
+ switch (cur.batteryPlugType) {
+ case 1:
+ cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
+ break;
+ case 2:
+ cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
+ break;
+ case 3:
+ cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
+ break;
+ }
cur.numReadInts += 1;
if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
+ Integer.toHexString(stateInt)
@@ -1968,6 +2004,45 @@
public void noteEventLocked(int code, String name, int uid) {
uid = mapUid(uid);
+ if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
+ int idx = code&~HistoryItem.EVENT_FLAG_START;
+ HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
+ if (active == null) {
+ active = new HashMap<String, SparseBooleanArray>();
+ mActiveEvents[idx] = active;
+ }
+ SparseBooleanArray uids = active.get(name);
+ if (uids == null) {
+ uids = new SparseBooleanArray();
+ active.put(name, uids);
+ }
+ if (uids.get(uid)) {
+ // Already set, nothing to do!
+ return;
+ }
+ uids.put(uid, true);
+ } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+ int idx = code&~HistoryItem.EVENT_FLAG_FINISH;
+ HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
+ if (active == null) {
+ // not currently active, nothing to do.
+ return;
+ }
+ SparseBooleanArray uids = active.get(name);
+ if (uids == null) {
+ // not currently active, nothing to do.
+ return;
+ }
+ idx = uids.indexOfKey(uid);
+ if (idx < 0 || !uids.valueAt(idx)) {
+ // not currently active, nothing to do.
+ return;
+ }
+ uids.removeAt(idx);
+ if (uids.size() <= 0) {
+ active.remove(name);
+ }
+ }
addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
}
@@ -5125,6 +5200,7 @@
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOff = 0;
}
+ initActiveHistoryEventsLocked(mSecRealtime);
}
private void resetAllStatsLocked() {
@@ -5172,6 +5248,23 @@
clearHistoryLocked();
}
+ private void initActiveHistoryEventsLocked(long nowRealtime) {
+ for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+ HashMap<String, SparseBooleanArray> active = mActiveEvents[i];
+ if (active == null) {
+ continue;
+ }
+ for (HashMap.Entry<String, SparseBooleanArray> ent : active.entrySet()) {
+ SparseBooleanArray uids = ent.getValue();
+ for (int j=0; j<uids.size(); j++) {
+ if (uids.valueAt(j)) {
+ addHistoryEventLocked(nowRealtime, i, ent.getKey(), uids.keyAt(j));
+ }
+ }
+ }
+ }
+ }
+
void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
if (oldScreenOn) {
int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
@@ -5221,12 +5314,14 @@
// battery was last full, or the level is at 100, or
// 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
|| level >= 90
|| (mDischargeCurrentLevel < 20 && level >= 80)) {
doWrite = true;
resetAllStatsLocked();
mDischargeStartLevel = level;
+ reset = true;
}
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
@@ -5249,6 +5344,9 @@
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOff = 0;
doUnplugLocked(realtime, mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
+ if (reset) {
+ initActiveHistoryEventsLocked(mSecRealtime);
+ }
} else {
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 5469b63..c957b67 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -20,6 +20,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import com.android.internal.app.ActionBarImpl;
import android.content.Context;
@@ -96,7 +97,7 @@
if (mLastSystemUiVisibility != 0) {
int newVis = mLastSystemUiVisibility;
onWindowSystemUiVisibilityChanged(newVis);
- requestFitSystemWindows();
+ requestApplyInsets();
}
}
}
@@ -152,7 +153,7 @@
}
if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
if (mActionBar != null) {
- requestFitSystemWindows();
+ requestApplyInsets();
}
}
}
@@ -190,19 +191,20 @@
}
@Override
- protected boolean fitSystemWindows(Rect insets) {
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
pullChildren();
final int vis = getWindowSystemUiVisibility();
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+ final Rect systemInsets = insets.getSystemWindowInsets();
// The top and bottom action bars are always within the content area.
- boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
+ boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
if (mActionBarBottom != null) {
- changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+ changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
}
- mBaseInnerInsets.set(insets);
+ mBaseInnerInsets.set(systemInsets);
computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
changed = true;
@@ -215,9 +217,9 @@
// We don't do any more at this point. To correctly compute the content/inner
// insets in all cases, we need to know the measured size of the various action
- // bar elements. fitSystemWindows() happens before the measure pass, so we can't
+ // bar elements. onApplyWindowInsets() happens before the measure pass, so we can't
// do that here. Instead we will take this up in onMeasure().
- return true;
+ return WindowInsets.EMPTY;
}
@Override
@@ -321,7 +323,7 @@
// the app's fitSystemWindows(). We do this before measuring the content
// view to keep the same semantics as the normal fitSystemWindows() call.
mLastInnerInsets.set(mInnerInsets);
- super.fitSystemWindows(mInnerInsets);
+ mContent.dispatchApplyWindowInsets(new WindowInsets(mInnerInsets));
}
measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 3e1f26a..fae93ba 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -474,6 +474,12 @@
bitmapCreateFlags, ninePatchChunk, layoutBounds, -1);
}
+// Need to buffer enough input to be able to rewind as much as might be read by a decoder
+// trying to determine the stream's format. Currently the most is 64, read by
+// SkImageDecoder_libwebp.
+// FIXME: Get this number from SkImageDecoder
+#define BYTES_TO_BUFFER 64
+
static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
jobject padding, jobject options) {
@@ -481,11 +487,8 @@
SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
if (stream.get()) {
- // Need to buffer enough input to be able to rewind as much as might be read by a decoder
- // trying to determine the stream's format. Currently the most is 64, read by
- // SkImageDecoder_libwebp.
- // FIXME: Get this number from SkImageDecoder
- SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
+ SkAutoTUnref<SkStreamRewindable> bufferedStream(
+ SkFrontBufferedStream::Create(stream, BYTES_TO_BUFFER));
SkASSERT(bufferedStream.get() != NULL);
// for now we don't allow purgeable with java inputstreams
bitmap = doDecode(env, bufferedStream, padding, options, false, false);
@@ -506,30 +509,48 @@
return nullObjectReturn("fstat return -1");
}
- bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions);
- bool isShareable = optionsShareable(env, bitmapFactoryOptions);
- bool weOwnTheFD = false;
- if (isPurgeable && isShareable) {
- int newFD = ::dup(descriptor);
- if (-1 != newFD) {
- weOwnTheFD = true;
- descriptor = newFD;
- }
- }
+ // Restore the descriptor's offset on exiting this function.
+ AutoFDSeek autoRestore(descriptor);
FILE* file = fdopen(descriptor, "r");
if (file == NULL) {
return nullObjectReturn("Could not open file");
}
- SkAutoTUnref<SkFILEStream> stream(new SkFILEStream(file,
- weOwnTheFD ? SkFILEStream::kCallerPasses_Ownership :
+ SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
SkFILEStream::kCallerRetains_Ownership));
- /* Allow purgeable iff we own the FD, i.e., in the puregeable and
- shareable case.
- */
- return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD);
+ SkAutoTUnref<SkStreamRewindable> stream;
+
+ // Retain the old behavior of allowing purgeable if both purgeable and
+ // shareable are set to true.
+ bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions)
+ && optionsShareable(env, bitmapFactoryOptions);
+ if (isPurgeable) {
+ // Copy the stream, so the image can be decoded multiple times without
+ // continuing to modify the original file descriptor.
+ // Copy beginning from the current position.
+ const size_t fileSize = fileStream->getLength() - fileStream->getPosition();
+ void* buffer = sk_malloc_flags(fileSize, 0);
+ if (buffer == NULL) {
+ return nullObjectReturn("Could not make a copy for ashmem");
+ }
+
+ SkAutoTUnref<SkData> data(SkData::NewFromMalloc(buffer, fileSize));
+
+ if (fileStream->read(buffer, fileSize) != fileSize) {
+ return nullObjectReturn("Could not read the file.");
+ }
+
+ stream.reset(new SkMemoryStream(data));
+ } else {
+ // Use a buffered stream. Although an SkFILEStream can be rewound, this
+ // ensures that SkImageDecoder::Factory never rewinds beyond the
+ // current position of the file descriptor.
+ stream.reset(SkFrontBufferedStream::Create(fileStream, BYTES_TO_BUFFER));
+ }
+
+ return doDecode(env, stream, padding, bitmapFactoryOptions, isPurgeable);
}
static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 2cb2812..e98d45b 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -327,9 +327,10 @@
}
static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle,
- SkPath* path, jint op) {
+ jlong pathHandle, jint op) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
- bool result = canvas->clipPath(*path, static_cast<SkRegion::Op>(op));
+ bool result = canvas->clipPath(*reinterpret_cast<SkPath*>(pathHandle),
+ static_cast<SkRegion::Op>(op));
return result ? JNI_TRUE : JNI_FALSE;
}
@@ -342,9 +343,9 @@
}
static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle,
- SkDrawFilter* filter) {
+ jlong filterHandle) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
- canvas->setDrawFilter(filter);
+ canvas->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
}
static jboolean quickReject__RectF(JNIEnv* env, jobject, jlong canvasHandle,
@@ -356,9 +357,9 @@
}
static jboolean quickReject__Path(JNIEnv* env, jobject, jlong canvasHandle,
- SkPath* path) {
+ jlong pathHandle) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
- bool result = canvas->quickReject(*path);
+ bool result = canvas->quickReject(*reinterpret_cast<SkPath*>(pathHandle));
return result ? JNI_TRUE : JNI_FALSE;
}
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index da40acff..09589bd 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -23,7 +23,6 @@
#include "SkColorMatrixFilter.h"
#include "SkPorterDuff.h"
-#include <SkiaColorFilter.h>
#include <Caches.h>
namespace android {
@@ -32,64 +31,9 @@
class SkColorFilterGlue {
public:
- static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong fHandle) {
- SkColorFilter* obj = reinterpret_cast<SkColorFilter *>(objHandle);
- SkiaColorFilter* f = reinterpret_cast<SkiaColorFilter *>(fHandle);
- if (obj) SkSafeUnref(obj);
- // f == NULL when not !USE_OPENGL_RENDERER, so no need to delete outside the ifdef
-#ifdef USE_OPENGL_RENDERER
- if (f && android::uirenderer::Caches::hasInstance()) {
- android::uirenderer::Caches::getInstance().resourceCache.destructor(f);
- } else {
- delete f;
- }
-#endif
- }
-
- static jlong glCreatePorterDuffFilter(JNIEnv* env, jobject, jlong skFilterHandle,
- jint srcColor, jint modeHandle) {
- SkColorFilter *skFilter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
- SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
-#ifdef USE_OPENGL_RENDERER
- return reinterpret_cast<jlong>(new SkiaBlendFilter(skFilter, srcColor, SkPorterDuff::ToXfermodeMode(mode)));
-#else
- return NULL;
-#endif
- }
-
- static jlong glCreateLightingFilter(JNIEnv* env, jobject, jlong skFilterHandle,
- jint mul, jint add) {
- SkColorFilter *skFilter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
-#ifdef USE_OPENGL_RENDERER
- return reinterpret_cast<jlong>(new SkiaLightingFilter(skFilter, mul, add));
-#else
- return NULL;
-#endif
- }
-
- static jlong glCreateColorMatrixFilter(JNIEnv* env, jobject, jlong skFilterHandle,
- jfloatArray jarray) {
- SkColorFilter *skFilter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
-#ifdef USE_OPENGL_RENDERER
- AutoJavaFloatArray autoArray(env, jarray, 20);
- const float* src = autoArray.ptr();
-
- float* colorMatrix = new float[16];
- memcpy(colorMatrix, src, 4 * sizeof(float));
- memcpy(&colorMatrix[4], &src[5], 4 * sizeof(float));
- memcpy(&colorMatrix[8], &src[10], 4 * sizeof(float));
- memcpy(&colorMatrix[12], &src[15], 4 * sizeof(float));
-
- float* colorVector = new float[4];
- colorVector[0] = src[4];
- colorVector[1] = src[9];
- colorVector[2] = src[14];
- colorVector[3] = src[19];
-
- return reinterpret_cast<jlong>(new SkiaColorMatrixFilter(skFilter, colorMatrix, colorVector));
-#else
- return NULL;
-#endif
+ static void finalizer(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
+ SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
+ if (filter) SkSafeUnref(filter);
}
static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
@@ -119,22 +63,19 @@
};
static JNINativeMethod colorfilter_methods[] = {
- {"destroyFilter", "(JJ)V", (void*) SkColorFilterGlue::finalizer}
+ {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
};
static JNINativeMethod porterduff_methods[] = {
{ "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
- { "nCreatePorterDuffFilter", "(JII)J", (void*) SkColorFilterGlue::glCreatePorterDuffFilter }
};
static JNINativeMethod lighting_methods[] = {
{ "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
- { "nCreateLightingFilter", "(JII)J", (void*) SkColorFilterGlue::glCreateLightingFilter },
};
static JNINativeMethod colormatrix_methods[] = {
{ "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
- { "nColorMatrixFilter", "(J[F)J", (void*) SkColorFilterGlue::glCreateColorMatrixFilter }
};
#define REG(env, name, array) \
diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp
index acc2276..89d64fa 100644
--- a/core/jni/android_database_SQLiteGlobal.cpp
+++ b/core/jni/android_database_SQLiteGlobal.cpp
@@ -39,7 +39,7 @@
bool verboseLog = !!data;
if (iErrCode == 0 || iErrCode == SQLITE_CONSTRAINT || iErrCode == SQLITE_SCHEMA) {
if (verboseLog) {
- ALOGV(LOG_VERBOSE, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
+ ALOG(LOG_VERBOSE, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
}
} else {
ALOG(LOG_ERROR, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg);
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 2b85fef..db84d000 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -411,7 +411,7 @@
ScopedUtfChars pathname(env, pathnameStr);
if (pathname.c_str() == NULL) {
- ALOGV("restorecon(%p) => threw exception", pathname);
+ ALOGV("restorecon(%p) => threw exception", pathnameStr);
return false;
}
diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp
index 9379375..de68b97 100644
--- a/core/jni/android_view_DisplayList.cpp
+++ b/core/jni/android_view_DisplayList.cpp
@@ -117,6 +117,12 @@
displayList->setProjectBackwards(shouldProject);
}
+static void android_view_DisplayList_setProjectionReceiver(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean shouldRecieve) {
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+ displayList->setProjectionReceiver(shouldRecieve);
+}
+
static void android_view_DisplayList_setOutline(JNIEnv* env,
jobject clazz, jlong displayListPtr, jlong outlinePathPtr) {
DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -124,6 +130,24 @@
displayList->setOutline(outline);
}
+static void android_view_DisplayList_setClipToOutline(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean clipToOutline) {
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+ displayList->setClipToOutline(clipToOutline);
+}
+
+static void android_view_DisplayList_setCastsShadow(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean castsShadow) {
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+ displayList->setCastsShadow(castsShadow);
+}
+
+static void android_view_DisplayList_setSharesGlobalCamera(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean sharesGlobalCamera) {
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+ displayList->setSharesGlobalCamera(sharesGlobalCamera);
+}
+
static void android_view_DisplayList_setAlpha(JNIEnv* env,
jobject clazz, jlong displayListPtr, float alpha) {
DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -391,8 +415,12 @@
{ "nSetAnimationMatrix", "(JJ)V", (void*) android_view_DisplayList_setAnimationMatrix },
{ "nSetClipToBounds", "(JZ)V", (void*) android_view_DisplayList_setClipToBounds },
{ "nSetIsolatedZVolume", "(JZ)V", (void*) android_view_DisplayList_setIsolatedZVolume },
- { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards },
+ { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards },
+ { "nSetProjectionReceiver","(JZ)V", (void*) android_view_DisplayList_setProjectionReceiver },
{ "nSetOutline", "(JJ)V", (void*) android_view_DisplayList_setOutline },
+ { "nSetClipToOutline", "(JZ)V", (void*) android_view_DisplayList_setClipToOutline },
+ { "nSetCastsShadow", "(JZ)V", (void*) android_view_DisplayList_setCastsShadow },
+ { "nSetSharesGlobalCamera","(JZ)V", (void*) android_view_DisplayList_setSharesGlobalCamera },
{ "nSetAlpha", "(JF)V", (void*) android_view_DisplayList_setAlpha },
{ "nSetHasOverlappingRendering", "(JZ)V",
(void*) android_view_DisplayList_setHasOverlappingRendering },
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 6cc94e3..b854fb9 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -47,7 +47,6 @@
#include <LayerRenderer.h>
#include <OpenGLRenderer.h>
#include <SkiaShader.h>
-#include <SkiaColorFilter.h>
#include <Stencil.h>
#include <Rect.h>
@@ -81,7 +80,6 @@
#define MODIFIER_SHADOW 1
#define MODIFIER_SHADER 2
-#define MODIFIER_COLOR_FILTER 4
// ----------------------------------------------------------------------------
@@ -197,18 +195,6 @@
env->ReleaseStringUTFChars(name, valueCharArray);
}
-static void android_view_GLES20Canvas_setCountOverdrawEnabled(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jboolean enabled) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- renderer->setCountOverdrawEnabled(enabled);
-}
-
-static jfloat android_view_GLES20Canvas_getOverdraw(JNIEnv* env, jobject clazz,
- jlong rendererPtr) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- return renderer->getOverdraw();
-}
-
// ----------------------------------------------------------------------------
// Functor
// ----------------------------------------------------------------------------
@@ -222,7 +208,7 @@
}
static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jint functorPtr) {
+ jobject clazz, jlong rendererPtr, jlong functorPtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
renderer->detachFunctor(functor);
@@ -650,7 +636,6 @@
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
if (modifiers & MODIFIER_SHADOW) renderer->resetShadow();
if (modifiers & MODIFIER_SHADER) renderer->resetShader();
- if (modifiers & MODIFIER_COLOR_FILTER) renderer->resetColorFilter();
}
static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz,
@@ -660,12 +645,6 @@
renderer->setupShader(shader);
}
-static void android_view_GLES20Canvas_setupColorFilter(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jlong colorFilterPtr) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- SkiaColorFilter* colorFilter = reinterpret_cast<SkiaColorFilter*>(colorFilterPtr);
- renderer->setupColorFilter(colorFilter);
-}
static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
jlong rendererPtr, jfloat radius, jfloat dx, jfloat dy, jint color) {
@@ -999,7 +978,7 @@
jlong layerPtr, jlong colorFilterPtr) {
Layer* layer = reinterpret_cast<Layer*>(layerPtr);
if (layer) {
- SkiaColorFilter* colorFilter = reinterpret_cast<SkiaColorFilter*>(colorFilterPtr);
+ SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
layer->setColorFilter(colorFilter);
}
}
@@ -1176,8 +1155,6 @@
{ "nSetProperty", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) android_view_GLES20Canvas_setProperty },
- { "nSetCountOverdrawEnabled", "(JZ)V", (void*) android_view_GLES20Canvas_setCountOverdrawEnabled },
- { "nGetOverdraw", "(J)F", (void*) android_view_GLES20Canvas_getOverdraw },
{ "nGetStencilSize", "()I", (void*) android_view_GLES20Canvas_getStencilSize },
@@ -1236,7 +1213,6 @@
{ "nResetModifiers", "(JI)V", (void*) android_view_GLES20Canvas_resetModifiers },
{ "nSetupShader", "(JJ)V", (void*) android_view_GLES20Canvas_setupShader },
- { "nSetupColorFilter", "(JJ)V", (void*) android_view_GLES20Canvas_setupColorFilter },
{ "nSetupShadow", "(JFFFI)V", (void*) android_view_GLES20Canvas_setupShadow },
{ "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 616f5ab4..93e68eb 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -140,7 +140,7 @@
touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
- FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS);
+ assertTrue(FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS));
assertDirContents("file1", "file2", "file3");
}
@@ -148,13 +148,13 @@
touch("file1", -HOUR_IN_MILLIS);
touch("file2", HOUR_IN_MILLIS);
touch("file3", WEEK_IN_MILLIS);
- FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+ assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
assertDirContents("file1", "file2");
touch("file1", -HOUR_IN_MILLIS);
touch("file2", HOUR_IN_MILLIS);
touch("file3", WEEK_IN_MILLIS);
- FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+ assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
assertDirContents("file1", "file2");
}
@@ -164,7 +164,8 @@
touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
- FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+ assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
+ assertFalse(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
assertDirContents("file1");
}
@@ -174,7 +175,8 @@
touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
- FileUtils.deleteOlderFiles(mDir, 2, 0);
+ assertTrue(FileUtils.deleteOlderFiles(mDir, 2, 0));
+ assertFalse(FileUtils.deleteOlderFiles(mDir, 2, 0));
assertDirContents("file1", "file2");
}
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
index b501f20..6f92c78b 100644
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -7,6 +7,34 @@
<p>Android developers, their apps, and their successes with Android and Google Play. </p>
+<div id="Kiwi" style="background: #F0F0F0;
+ border-top: 1px solid #DDD;
+ padding: 0px 0 24px 0;
+ overflow: auto;
+ clear:both;
+ margin-bottom:40px;
+ margin-top:30px;">
+ <div style="padding:0 0 0 29px;">
+ <h4>Developer Story: Kiwi, Inc.</h4>
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 17px 20px 9px 0;"
+ src="//lh4.ggpht.com/qUI-8MJy70l4qoVBR_sx-56ckR_m0R_ZXcJ1DiTYUR3R_owWzsCFTYkAk4p5DMnaSdY3=w124" >
+ <div style="width:700px;">
+ <p style="margin-top:26px;
+ margin-bottom:12px;">
+ Android-first developer <a href="//play.google.com/store/apps/developer?id=Kiwi,+Inc." target="_android">Kiwi, Inc.</a> has five of the top 25 grossing games on Google Play, including <a href="https://play.google.com/store/apps/details?id=com.kiwi.shipwrecked" target="_android">Shipwrecked: Lost Island</a>, <a href="https://play.google.com/store/apps/details?id=com.kiwi.monsterpark" target="_android">Monsterama Park</a>, and <a href="https://play.google.com/store/apps/details?id=com.kiwi.mysteryestate" target="_android">Hidden Object: Mystery Estate</a>. Hear how Google Play helped them double revenue every six months with features like instant updates, staged rollouts, and more.</p>
+ </div>
+ <iframe style="float:left;
+ margin-right:24px;
+ margin-top:14px;" width="700" height="394" src=
+ "http://www.youtube.com/embed/WWArLD6nqrk?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
+ </iframe>
+ </div>
+</div>
<div style="background: #F0F0F0;
border-top: 1px solid #DDD;
padding: 0px 0 24px 0;
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index 916ecee..ac446dc 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -75,7 +75,7 @@
{@code dependency} section of your application's {@code build.gradle} file:</p>
<pre>dependencies {
- compile: "com.google.android.gms:play-services:3.1.+"
+ compile "com.google.android.gms:play-services:3.1.+"
}
</pre>
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index d2e65d4..4cfe1bc 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -64,14 +64,10 @@
<li>Under <strong>Public API access</strong>, click <strong>Create new key</strong>.</li>
-<li>In the <strong>Create a new key</strong> dialog, click <strong>Android key</strong>.</li>
+<li>In the <strong>Create a new key</strong> dialog, click <strong>Server key</strong>.</li>
-<li>In the resulting configuration dialog, supply one SHA1 fingerprint and
-the package name for your app, separated by a semicolon. For example,
-{@code 45:B5:E4:6F:36:AD:0A:98:94:B4:02:66:2B:12:17:F2:56:26:A0:E0;com.myexample}.
-<p>To get the value for the SHA1 fingerprint, follow the instructions in the
-<a href="http://developers.google.com/console/help/new/#installedapplications">console
-help</a>.</p></li>
+<li>In the resulting configuration dialog, supply your server's IP address. For testing
+purposes, you can use {@code 0.0.0.0/0}.</p></li>
<li>Click <strong>Create</strong>.</li>
<li>In the refreshed page, copy the
@@ -102,4 +98,3 @@
<li>Write your client app. This is the GCM-enabled Android application that runs
on a device. See <a href="client.html">Implementing GCM Client</a> for more information.</li>
</ol>
-
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
index 7ba1bd5..ccd1267 100644
--- a/docs/html/google/gcm/server.jd
+++ b/docs/html/google/gcm/server.jd
@@ -120,7 +120,6 @@
<li>Able to store the API key and client registration IDs. The
API key is included in the header of POST requests that send
messages.</li>
- <li>Able to store the API key and client registration IDs.</li>
<li>Able to generate message IDs to uniquely identify each message it sends.</li>
</ul>
diff --git a/docs/html/guide/topics/resources/runtime-changes.jd b/docs/html/guide/topics/resources/runtime-changes.jd
index 695647b..0e03fe0 100644
--- a/docs/html/guide/topics/resources/runtime-changes.jd
+++ b/docs/html/guide/topics/resources/runtime-changes.jd
@@ -53,7 +53,7 @@
<ol type="a">
<li><a href="#RetainingAnObject">Retain an object during a configuration change</a>
<p>Allow your activity to restart when a configuration changes, but carry a stateful
-{@link java.lang.Object} to the new instance of your activity.</p>
+object to the new instance of your activity.</p>
</li>
<li><a href="#HandlingTheChange">Handle the configuration change yourself</a>
@@ -73,40 +73,53 @@
android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} callback—it is not
designed to carry large objects (such as bitmaps) and the data within it must be serialized then
deserialized, which can consume a lot of memory and make the configuration change slow. In such a
-situation, you can alleviate the burden of reinitializing your activity by retaining a stateful
-{@link java.lang.Object} when your activity is restarted due to a configuration change.</p>
+situation, you can alleviate the burden of reinitializing your activity by retaining a {@link
+android.app.Fragment} when your activity is restarted due to a configuration change. This fragment
+can contain references to stateful objects that you want to retain.</p>
-<p>To retain an object during a runtime configuration change:</p>
+<p>When the Android system shuts down your activity due to a configuration change, the fragments
+of your activity that you have marked to retain are not destroyed. You can add such fragments to
+your activity to preserve stateful objects.</p>
+
+<p>To retain stateful objects in a fragment during a runtime configuration change:</p>
+
<ol>
- <li>Override the {@link android.app.Activity#onRetainNonConfigurationInstance()} method to return
-the object you would like to retain.</li>
- <li>When your activity is created again, call {@link
-android.app.Activity#getLastNonConfigurationInstance()} to recover your object.</li>
+ <li>Extend the {@link android.app.Fragment} class and declare references to your stateful
+ objects.</li>
+ <li>Call {@link android.app.Fragment#setRetainInstance(boolean)} when the fragment is created.
+ </li>
+ <li>Add the fragment to your activity.</li>
+ <li>Use {@link android.app.FragmentManager} to retrieve the fragment when the activity is
+ restarted.</li>
</ol>
-<p>When the Android system shuts down your activity due to a configuration change, it calls {@link
-android.app.Activity#onRetainNonConfigurationInstance()} between the {@link
-android.app.Activity#onStop()} and {@link android.app.Activity#onDestroy()} callbacks. In your
-implementation of {@link android.app.Activity#onRetainNonConfigurationInstance()}, you can return
-any {@link java.lang.Object} that you need in order to efficiently restore your state after the
-configuration change.</p>
-
-<p>A scenario in which this can be valuable is if your application loads a lot of data from the
-web. If the user changes the orientation of the device and the activity restarts, your application
-must re-fetch the data, which could be slow. What you can do instead is implement
-{@link android.app.Activity#onRetainNonConfigurationInstance()} to return an object carrying your
-data and then retrieve the data when your activity starts again with {@link
-android.app.Activity#getLastNonConfigurationInstance()}. For example:</p>
+<p>For example, define your fragment as follows:</p>
<pre>
-@Override
-public Object onRetainNonConfigurationInstance() {
- final MyDataObject data = collectMyLoadedData();
- return data;
+public class RetainedFragment extends Fragment {
+
+ // data object we want to retain
+ private MyDataObject data;
+
+ // this method is only called once for this fragment
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // retain this fragment
+ setRetainInstance(true);
+ }
+
+ public void setData(MyDataObject data) {
+ this.data = data;
+ }
+
+ public MyDataObject getData() {
+ return data;
+ }
}
</pre>
-<p class="caution"><strong>Caution:</strong> While you can return any object, you
+<p class="caution"><strong>Caution:</strong> While you can store any object, you
should never pass an object that is tied to the {@link android.app.Activity}, such as a {@link
android.graphics.drawable.Drawable}, an {@link android.widget.Adapter}, a {@link android.view.View}
or any other object that's associated with a {@link android.content.Context}. If you do, it will
@@ -114,26 +127,51 @@
means that your application maintains a hold on them and they cannot be garbage-collected, so
lots of memory can be lost.)</p>
-<p>Then retrieve the data when your activity starts again:</p>
+<p>Then use {@link android.app.FragmentManager} to add the fragment to the activity.
+You can obtain the data object from the fragment when the activity starts again during runtime
+configuration changes. For example, define your activity as follows:</p>
<pre>
-@Override
-public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
+public class MyActivity extends Activity {
- final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
- if (data == null) {
- data = loadMyData();
+ private RetainedFragment dataFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ // find the retained fragment on activity restarts
+ FragmentManager fm = getFragmentManager();
+ dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
+
+ // create the fragment and data the first time
+ if (dataFragment == null) {
+ // add the fragment
+ dataFragment = new DataFragment();
+ fm.beginTransaction().add(dataFragment, “data”).commit();
+ // load the data from the web
+ dataFragment.setData(loadMyData());
+ }
+
+ // the data is available in dataFragment.getData()
+ ...
}
- ...
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ // store the data in the fragment
+ dataFragment.setData(collectMyLoadedData());
+ }
}
</pre>
-<p>In this case, {@link android.app.Activity#getLastNonConfigurationInstance()} returns the data
-saved by {@link android.app.Activity#onRetainNonConfigurationInstance()}. If {@code data} is null
-(which happens when the activity starts due to any reason other than a configuration change) then
-this code loads the data object from the original source.</p>
+<p>In this example, {@link android.app.Activity#onCreate(Bundle) onCreate()} adds a fragment
+or restores a reference to it. {@link android.app.Activity#onCreate(Bundle) onCreate()} also
+stores the stateful object inside the fragment instance.
+{@link android.app.Activity#onDestroy() onDestroy()} updates the stateful object inside the
+retained fragment instance.</p>
diff --git a/docs/html/images/video-kiwi.jpg b/docs/html/images/video-kiwi.jpg
new file mode 100644
index 0000000..1c1146c
--- /dev/null
+++ b/docs/html/images/video-kiwi.jpg
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 191e0fb..d976c1e 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -18,6 +18,52 @@
<!-- set explicit widths as needed to prevent overflow issues -->
<li class="item carousel-home">
+ <div class="content-left col-11" style="padding-top:65px;">
+ <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
+ <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
+ <div id="ytapiplayer">
+ <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+ </div>
+ <script type="text/javascript">
+ var params = { allowScriptAccess: "always" };
+ var atts = { id: "ytapiplayer" };
+ swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+ "ytapiplayer", "600", "336", "8", null, null, params, atts);
+
+ // Callback used to pause/resume carousel based on video state
+ function onytplayerStateChange(newState) {
+ var isPaused = $("#pauseButton").hasClass("paused");
+ if ((newState == 1) || (newState == 3)) {
+ // if playing or buffering, pause the carousel
+ if (!isPaused) {
+ $("#pauseButton").click();
+ }
+ } else {
+ // otherwise, make sure carousel is running
+ if (isPaused) {
+ $("#pauseButton").click();
+ }
+ }
+ }
+
+ // Callback received when YouTube player loads to setup callback (above)
+ function onYouTubePlayerReady(playerId) {
+ var ytplayer = document.getElementById("ytapiplayer");
+ ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
+ }
+
+ </script>
+ </div>
+ </div>
+ <div class="content-right col-4">
+ <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
+ <p>Game developer Kiwi has five of the top 25 grossing titles on Google Play. Hear how Google Play
+ has helped them double revenue every six months.</p>
+ <p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p>
+ </div>
+ </li>
+
+ <li class="item carousel-home">
<div class="content-left col-7" style="width:400px;">
<a href="{@docRoot}about/versions/kitkat.html">
<img src="{@docRoot}images/home/kk-hero.jpg" width="242" style="padding-top:72px;">
diff --git a/docs/html/tools/help/proguard.jd b/docs/html/tools/help/proguard.jd
index 3ba7db2..aa9a0bc 100644
--- a/docs/html/tools/help/proguard.jd
+++ b/docs/html/tools/help/proguard.jd
@@ -25,11 +25,14 @@
<h2>See also</h2>
<ol>
- <li><a href="http://proguard.sourceforge.net/manual/introduction.html">ProGuard
- Manual »</a></li>
-
- <li><a href="http://proguard.sourceforge.net/manual/retrace/introduction.html">ProGuard
- ReTrace Manual »</a></li>
+ <li>
+ <a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">ProGuard
+ Manual »</a>
+ </li>
+ <li>
+ <a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/retrace/introduction.html">ProGuard
+ ReTrace Manual »</a>
+ </li>
</ol>
</div>
</div>
@@ -146,14 +149,14 @@
</pre>
<p>There are many options and considerations when using the <code>-keep</code> option, so it is
- highly recommended that you read the <a href="http://proguard.sourceforge.net/manual/introduction.html">ProGuard
- Manual</a> for more information about customizing your configuration file. The <a href=
- "http://proguard.sourceforge.net/manual/usage.html#keepoverview">Overview of Keep options</a> and
- <a href="http://proguard.sourceforge.net/index.html#/manual/examples.html">Examples section</a>
- are particularly helpful. The <a href=
- "http://proguard.sourceforge.net/manual/troubleshooting.html">Troubleshooting</a> section of the
- ProGuard Manual outlines other common problems you might encounter when your code gets stripped
- away.</p>
+ highly recommended that you read the
+ <a href="http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/introduction.html">ProGuard
+ Manual</a> for more information about customizing your configuration file. The
+ <em>Overview of Keep options</em> and <em>Examples</em> sections are particularly helpful.
+ The <a href=
+ "http://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/troubleshooting.html">Troubleshooting
+ </a> section of the ProGuard Manual outlines other common problems you might encounter
+ when your code gets stripped away.</p>
<h2 id="decoding">Decoding Obfuscated Stack Traces</h2>
@@ -192,4 +195,4 @@
<p>How you save the <code>mapping.txt</code> file is your decision. For example, you can rename them to
include a version or build number, or you can version control them along with your source
- code.</p>
\ No newline at end of file
+ code.</p>
diff --git a/docs/html/training/animation/screen-slide.jd b/docs/html/training/animation/screen-slide.jd
index 07d779f..a68d475 100644
--- a/docs/html/training/animation/screen-slide.jd
+++ b/docs/html/training/animation/screen-slide.jd
@@ -63,22 +63,23 @@
contains a text view to display some text:
<pre>
-<com.example.android.animationsdemo.ScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content"
+<!-- fragment_screen_slide_page.xml -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent" >
- <TextView style="?android:textAppearanceMedium"
- android:padding="16dp"
- android:lineSpacingMultiplier="1.2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/lorem_ipsum" />
-
-</com.example.android.animationsdemo.ScrollView>
+ <TextView style="?android:textAppearanceMedium"
+ android:padding="16dp"
+ android:lineSpacingMultiplier="1.2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/lorem_ipsum" />
+</ScrollView>
</pre>
+ <p>Define also a string for the contents of the fragment.</p>
+
<h2 id="fragment">Create the Fragment</h2>
<p>Create a {@link android.support.v4.app.Fragment} class that returns the layout
that you just created in the {@link android.app.Fragment#onCreateView onCreateView()}
@@ -87,6 +88,8 @@
<pre>
+import android.support.v4.app.Fragment;
+...
public class ScreenSlidePageFragment extends Fragment {
@Override
@@ -111,6 +114,7 @@
<p>To begin, create a layout that contains a {@link android.support.v4.view.ViewPager}:</p>
<pre>
+<!-- activity_screen_slide.xml -->
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
@@ -133,6 +137,9 @@
</ul>
<pre>
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+...
public class ScreenSlidePagerActivity extends FragmentActivity {
/**
* The number of pages (wizard steps) to show in this demo.
@@ -153,11 +160,11 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_screen_slide_pager);
+ setContentView(R.layout.activity_screen_slide);
// Instantiate a ViewPager and a PagerAdapter.
mPager = (ViewPager) findViewById(R.id.pager);
- mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
+ mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
}
@@ -224,9 +231,9 @@
<code>ZoomOutPageTransformer</code>, you can set your custom animations
like this:</p>
<pre>
-ViewPager pager = (ViewPager) findViewById(R.id.pager);
+ViewPager mPager = (ViewPager) findViewById(R.id.pager);
...
-pager.setPageTransformer(true, new ZoomOutPageTransformer());
+mPager.setPageTransformer(true, new ZoomOutPageTransformer());
</pre>
@@ -257,8 +264,8 @@
<pre>
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
- private static float MIN_SCALE = 0.85f;
- private static float MIN_ALPHA = 0.5f;
+ private static final float MIN_SCALE = 0.85f;
+ private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
@@ -332,7 +339,7 @@
<pre>
public class DepthPageTransformer implements ViewPager.PageTransformer {
- private static float MIN_SCALE = 0.75f;
+ private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
diff --git a/drm/java/android/drm/DrmOutputStream.java b/drm/java/android/drm/DrmOutputStream.java
index 87677b8..22e7ac2 100644
--- a/drm/java/android/drm/DrmOutputStream.java
+++ b/drm/java/android/drm/DrmOutputStream.java
@@ -18,18 +18,23 @@
import static android.drm.DrmConvertedStatus.STATUS_OK;
import static android.drm.DrmManagerClient.INVALID_SESSION;
+import static libcore.io.OsConstants.SEEK_SET;
+import android.os.ParcelFileDescriptor;
import android.util.Log;
+import libcore.io.ErrnoException;
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+import libcore.io.Streams;
+
+import java.io.FileDescriptor;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import java.io.RandomAccessFile;
import java.net.UnknownServiceException;
import java.util.Arrays;
-import libcore.io.Streams;
-
/**
* Stream that applies a {@link DrmManagerClient} transformation to data before
* writing to disk, similar to a {@link FilterOutputStream}.
@@ -40,17 +45,19 @@
private static final String TAG = "DrmOutputStream";
private final DrmManagerClient mClient;
- private final RandomAccessFile mFile;
+ private final ParcelFileDescriptor mPfd;
+ private final FileDescriptor mFd;
private int mSessionId = INVALID_SESSION;
/**
- * @param file Opened with "rw" mode.
+ * @param pfd Opened with "rw" mode.
*/
- public DrmOutputStream(DrmManagerClient client, RandomAccessFile file, String mimeType)
+ public DrmOutputStream(DrmManagerClient client, ParcelFileDescriptor pfd, String mimeType)
throws IOException {
mClient = client;
- mFile = file;
+ mPfd = pfd;
+ mFd = pfd.getFileDescriptor();
mSessionId = mClient.openConvertSession(mimeType);
if (mSessionId == INVALID_SESSION) {
@@ -61,8 +68,12 @@
public void finish() throws IOException {
final DrmConvertedStatus status = mClient.closeConvertSession(mSessionId);
if (status.statusCode == STATUS_OK) {
- mFile.seek(status.offset);
- mFile.write(status.convertedData);
+ try {
+ Libcore.os.lseek(mFd, status.offset, SEEK_SET);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
+ IoBridge.write(mFd, status.convertedData, 0, status.convertedData.length);
mSessionId = INVALID_SESSION;
} else {
throw new IOException("Unexpected DRM status: " + status.statusCode);
@@ -75,7 +86,7 @@
Log.w(TAG, "Closing stream without finishing");
}
- mFile.close();
+ mPfd.close();
}
@Override
@@ -92,7 +103,7 @@
final DrmConvertedStatus status = mClient.convertData(mSessionId, exactBuffer);
if (status.statusCode == STATUS_OK) {
- mFile.write(status.convertedData);
+ IoBridge.write(mFd, status.convertedData, 0, status.convertedData.length);
} else {
throw new IOException("Unexpected DRM status: " + status.statusCode);
}
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index d3c1974..4838aa0 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -27,24 +27,21 @@
* never be used directly.
*/
public class ColorFilter {
- // Holds the pointer to the native SkColorFilter instance
- long native_instance;
-
/**
- * Holds the pointer to the native SkiaColorFilter instance, from libhwui.
+ * Holds the pointer to the native SkColorFilter instance.
*
* @hide
*/
- public long nativeColorFilter;
+ public long native_instance;
@Override
protected void finalize() throws Throwable {
try {
super.finalize();
} finally {
- destroyFilter(native_instance, nativeColorFilter);
+ destroyFilter(native_instance);
}
}
- static native void destroyFilter(long native_instance, long nativeColorFilter);
+ static native void destroyFilter(long native_instance);
}
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 3f7331d..7822c41 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -114,11 +114,9 @@
private void update() {
final float[] colorMatrix = mMatrix.getArray();
- destroyFilter(native_instance, nativeColorFilter);
+ destroyFilter(native_instance);
native_instance = nativeColorMatrixFilter(colorMatrix);
- nativeColorFilter = nColorMatrixFilter(native_instance, colorMatrix);
}
private static native long nativeColorMatrixFilter(float[] array);
- private static native long nColorMatrixFilter(long nativeFilter, float[] array);
}
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index 5829edf..70a3fe8 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -99,11 +99,9 @@
}
private void update() {
- destroyFilter(native_instance, nativeColorFilter);
+ destroyFilter(native_instance);
native_instance = native_CreateLightingFilter(mMul, mAdd);
- nativeColorFilter = nCreateLightingFilter(native_instance, mMul, mAdd);
}
private static native long native_CreateLightingFilter(int mul, int add);
- private static native long nCreateLightingFilter(long nativeFilter, int mul, int add);
}
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index 93fc1c7..c078c1c 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -91,12 +91,9 @@
}
private void update() {
- destroyFilter(native_instance, nativeColorFilter);
+ destroyFilter(native_instance);
native_instance = native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
- nativeColorFilter = nCreatePorterDuffFilter(native_instance, mColor, mMode.nativeInt);
}
private static native long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode);
- private static native long nCreatePorterDuffFilter(long nativeFilter, int srcColor,
- int porterDuffMode);
}
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 6799766..610465e 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -808,6 +808,19 @@
uint32_t lastPublicKey;
};
+// The most specific locale can consist of:
+//
+// - a 3 char language code
+// - a 3 char region code prefixed by a 'r'
+// - a 4 char script code prefixed by a 's'
+// - a 8 char variant code prefixed by a 'v'
+//
+// each separated by a single char separator, which sums up to a total of 24
+// chars, (25 include the string terminator) rounded up to 28 to be 4 byte
+// aligned.
+#define RESTABLE_MAX_LOCALE_LEN 28
+
+
/**
* Describes a particular resource configuration.
*/
@@ -828,10 +841,42 @@
union {
struct {
- // \0\0 means "any". Otherwise, en, fr, etc.
+ // This field can take three different forms:
+ // - \0\0 means "any".
+ //
+ // - Two 7 bit ascii values interpreted as ISO-639-1 language
+ // codes ('fr', 'en' etc. etc.). The high bit for both bytes is
+ // zero.
+ //
+ // - A single 16 bit little endian packed value representing an
+ // ISO-639-2 3 letter language code. This will be of the form:
+ //
+ // {1, t, t, t, t, t, s, s, s, s, s, f, f, f, f, f}
+ //
+ // bit[0, 4] = first letter of the language code
+ // bit[5, 9] = second letter of the language code
+ // bit[10, 14] = third letter of the language code.
+ // bit[15] = 1 always
+ //
+ // For backwards compatibility, languages that have unambiguous
+ // two letter codes are represented in that format.
+ //
+ // The layout is always bigendian irrespective of the runtime
+ // architecture.
char language[2];
- // \0\0 means "any". Otherwise, US, CA, etc.
+ // This field can take three different forms:
+ // - \0\0 means "any".
+ //
+ // - Two 7 bit ascii values interpreted as 2 letter region
+ // codes ('US', 'GB' etc.). The high bit for both bytes is zero.
+ //
+ // - An UN M.49 3 digit region code. For simplicity, these are packed
+ // in the same manner as the language codes, though we should need
+ // only 10 bits to represent them, instead of the 15.
+ //
+ // The layout is always bigendian irrespective of the runtime
+ // architecture.
char country[2];
};
uint32_t locale;
@@ -933,7 +978,7 @@
SDKVERSION_ANY = 0
};
- enum {
+ enum {
MINORVERSION_ANY = 0
};
@@ -1006,6 +1051,15 @@
uint32_t screenSizeDp;
};
+ // The ISO-15924 short name for the script corresponding to this
+ // configuration. (eg. Hant, Latn, etc.). Interpreted in conjunction with
+ // the locale field.
+ char localeScript[4];
+
+ // A single BCP-47 variant subtag. Will vary in length between 5 and 8
+ // chars. Interpreted in conjunction with the locale field.
+ char localeVariant[8];
+
void copyFromDeviceNoSwap(const ResTable_config& o);
void copyFromDtoH(const ResTable_config& o);
@@ -1063,7 +1117,46 @@
// settings is the requested settings
bool match(const ResTable_config& settings) const;
- void getLocale(char str[6]) const;
+ // Get the string representation of the locale component of this
+ // Config. The maximum size of this representation will be
+ // |RESTABLE_MAX_LOCALE_LEN| (including a terminating '\0').
+ //
+ // Example: en-US, en-Latn-US, en-POSIX.
+ void getBcp47Locale(char* out) const;
+
+ // Sets the values of language, region, script and variant to the
+ // well formed BCP-47 locale contained in |in|. The input locale is
+ // assumed to be valid and no validation is performed.
+ void setBcp47Locale(const char* in);
+
+ inline void clearLocale() {
+ locale = 0;
+ memset(localeScript, 0, sizeof(localeScript));
+ memset(localeVariant, 0, sizeof(localeVariant));
+ }
+
+ // Get the 2 or 3 letter language code of this configuration. Trailing
+ // bytes are set to '\0'.
+ size_t unpackLanguage(char language[4]) const;
+ // Get the 2 or 3 letter language code of this configuration. Trailing
+ // bytes are set to '\0'.
+ size_t unpackRegion(char region[4]) const;
+
+ // Sets the language code of this configuration to the first three
+ // chars at |language|.
+ //
+ // If |language| is a 2 letter code, the trailing byte must be '\0' or
+ // the BCP-47 separator '-'.
+ void packLanguage(const char* language);
+ // Sets the region code of this configuration to the first three bytes
+ // at |region|. If |region| is a 2 letter code, the trailing byte must be '\0'
+ // or the BCP-47 separator '-'.
+ void packRegion(const char* region);
+
+ // Returns a positive integer if this config is more specific than |o|
+ // with respect to their locales, a negative integer if |o| is more specific
+ // and 0 if they're equally specific.
+ int isLocaleMoreSpecificThan(const ResTable_config &o) const;
String8 toString() const;
};
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 8ad973d..6f8292d 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -94,6 +94,11 @@
private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER";
/**
+ * Package name for the Certificate Installer.
+ */
+ private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
+
+ /**
* Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
@@ -201,7 +206,7 @@
*/
public static Intent createInstallIntent() {
Intent intent = new Intent(ACTION_INSTALL);
- intent.setClassName("com.android.certinstaller",
+ intent.setClassName(CERT_INSTALLER_PACKAGE,
"com.android.certinstaller.CertInstallerMain");
return intent;
}
@@ -267,6 +272,7 @@
throw new NullPointerException("response == null");
}
Intent intent = new Intent(ACTION_CHOOSER);
+ intent.setPackage(CERT_INSTALLER_PACKAGE);
intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response));
intent.putExtra(EXTRA_HOST, host);
intent.putExtra(EXTRA_PORT, port);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 501b83e..9cea68c 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -463,17 +463,8 @@
if (locale) {
setLocaleLocked(locale);
} else if (config.language[0] != 0) {
- char spec[9];
- spec[0] = config.language[0];
- spec[1] = config.language[1];
- if (config.country[0] != 0) {
- spec[2] = '_';
- spec[3] = config.country[0];
- spec[4] = config.country[1];
- spec[5] = 0;
- } else {
- spec[3] = 0;
- }
+ char spec[RESTABLE_MAX_LOCALE_LEN];
+ config.getBcp47Locale(spec);
setLocaleLocked(spec);
} else {
updateResourceParamsLocked();
@@ -733,20 +724,11 @@
return;
}
- size_t llen = mLocale ? strlen(mLocale) : 0;
- mConfig->language[0] = 0;
- mConfig->language[1] = 0;
- mConfig->country[0] = 0;
- mConfig->country[1] = 0;
- if (llen >= 2) {
- mConfig->language[0] = mLocale[0];
- mConfig->language[1] = mLocale[1];
+ if (mLocale) {
+ mConfig->setBcp47Locale(mLocale);
+ } else {
+ mConfig->clearLocale();
}
- if (llen >= 5) {
- mConfig->country[0] = mLocale[3];
- mConfig->country[1] = mLocale[4];
- }
- mConfig->size = sizeof(*mConfig);
res->setParameters(mConfig);
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 72d331c..94d150a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -66,11 +66,6 @@
// size measured in sizeof(uint32_t)
#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
-static void printToLogFunc(int32_t cookie, const char* txt)
-{
- ALOGV("[cookie=%d] %s", cookie, txt);
-}
-
// Standard C isspace() is only required to look at the low byte of its input, so
// produces incorrect results for UTF-16 characters. For safety's sake, assume that
// any high-byte UTF-16 code point is not whitespace.
@@ -1539,6 +1534,71 @@
}
}
+/* static */ size_t unpackLanguageOrRegion(const char in[2], const char base,
+ char out[4]) {
+ if (in[0] & 0x80) {
+ // The high bit is "1", which means this is a packed three letter
+ // language code.
+
+ // The smallest 5 bits of the second char are the first alphabet.
+ const uint8_t first = in[1] & 0x1f;
+ // The last three bits of the second char and the first two bits
+ // of the first char are the second alphabet.
+ const uint8_t second = ((in[1] & 0xe0) >> 5) + ((in[0] & 0x03) << 3);
+ // Bits 3 to 7 (inclusive) of the first char are the third alphabet.
+ const uint8_t third = (in[0] & 0x7c) >> 2;
+
+ out[0] = first + base;
+ out[1] = second + base;
+ out[2] = third + base;
+ out[3] = 0;
+
+ return 3;
+ }
+
+ if (in[0]) {
+ memcpy(out, in, 2);
+ memset(out + 2, 0, 2);
+ return 2;
+ }
+
+ memset(out, 0, 4);
+ return 0;
+}
+
+/* static */ void packLanguageOrRegion(const char* in, const char base,
+ char out[2]) {
+ if (in[2] == 0 || in[2] == '-') {
+ out[0] = in[0];
+ out[1] = in[1];
+ } else {
+ uint8_t first = (in[0] - base) & 0x00ef;
+ uint8_t second = (in[1] - base) & 0x00ef;
+ uint8_t third = (in[2] - base) & 0x00ef;
+
+ out[0] = (0x80 | (third << 2) | (second >> 3));
+ out[1] = ((second << 5) | first);
+ }
+}
+
+
+void ResTable_config::packLanguage(const char* language) {
+ packLanguageOrRegion(language, 'a', this->language);
+}
+
+void ResTable_config::packRegion(const char* region) {
+ packLanguageOrRegion(region, '0', this->country);
+}
+
+size_t ResTable_config::unpackLanguage(char language[4]) const {
+ return unpackLanguageOrRegion(this->language, 'a', language);
+}
+
+size_t ResTable_config::unpackRegion(char region[4]) const {
+ return unpackLanguageOrRegion(this->country, '0', region);
+}
+
+
void ResTable_config::copyFromDtoH(const ResTable_config& o) {
copyFromDeviceNoSwap(o);
size = sizeof(ResTable_config);
@@ -1568,10 +1628,30 @@
screenHeightDp = htods(screenHeightDp);
}
+/* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) {
+ if (l.locale != r.locale) {
+ // NOTE: This is the old behaviour with respect to comparison orders.
+ // The diff value here doesn't make much sense (given our bit packing scheme)
+ // but it's stable, and that's all we need.
+ return l.locale - r.locale;
+ }
+
+ // The language & region are equal, so compare the scripts and variants.
+ int script = memcmp(l.localeScript, r.localeScript, sizeof(l.localeScript));
+ if (script) {
+ return script;
+ }
+
+ // The language, region and script are equal, so compare variants.
+ //
+ // This should happen very infrequently (if at all.)
+ return memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant));
+}
+
int ResTable_config::compare(const ResTable_config& o) const {
int32_t diff = (int32_t)(imsi - o.imsi);
if (diff != 0) return diff;
- diff = (int32_t)(locale - o.locale);
+ diff = compareLocales(*this, o);
if (diff != 0) return diff;
diff = (int32_t)(screenType - o.screenType);
if (diff != 0) return diff;
@@ -1598,18 +1678,15 @@
if (mnc != o.mnc) {
return mnc < o.mnc ? -1 : 1;
}
- if (language[0] != o.language[0]) {
- return language[0] < o.language[0] ? -1 : 1;
+
+ int diff = compareLocales(*this, o);
+ if (diff < 0) {
+ return -1;
}
- if (language[1] != o.language[1]) {
- return language[1] < o.language[1] ? -1 : 1;
+ if (diff > 0) {
+ return 1;
}
- if (country[0] != o.country[0]) {
- return country[0] < o.country[0] ? -1 : 1;
- }
- if (country[1] != o.country[1]) {
- return country[1] < o.country[1] ? -1 : 1;
- }
+
if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) {
return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1;
}
@@ -1656,7 +1733,6 @@
int diffs = 0;
if (mcc != o.mcc) diffs |= CONFIG_MCC;
if (mnc != o.mnc) diffs |= CONFIG_MNC;
- if (locale != o.locale) diffs |= CONFIG_LOCALE;
if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
if (density != o.density) diffs |= CONFIG_DENSITY;
if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
@@ -1671,9 +1747,44 @@
if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
+
+ const int diff = compareLocales(*this, o);
+ if (diff) diffs |= CONFIG_LOCALE;
+
return diffs;
}
+int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
+ if (locale || o.locale) {
+ if (language[0] != o.language[0]) {
+ if (!language[0]) return -1;
+ if (!o.language[0]) return 1;
+ }
+
+ if (country[0] != o.country[0]) {
+ if (!country[0]) return -1;
+ if (!o.country[0]) return 1;
+ }
+ }
+
+ // There isn't a well specified "importance" order between variants and
+ // scripts. We can't easily tell whether, say "en-Latn-US" is more or less
+ // specific than "en-US-POSIX".
+ //
+ // We therefore arbitrarily decide to give priority to variants over
+ // scripts since it seems more useful to do so. We will consider
+ // "en-US-POSIX" to be more specific than "en-Latn-US".
+
+ const int score = ((localeScript[0] != 0) ? 1 : 0) +
+ ((localeVariant[0] != 0) ? 2 : 0);
+
+ const int oScore = ((o.localeScript[0] != 0) ? 1 : 0) +
+ ((o.localeVariant[0] != 0) ? 2 : 0);
+
+ return score - oScore;
+
+}
+
bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
// The order of the following tests defines the importance of one
// configuration parameter over another. Those tests first are more
@@ -1691,14 +1802,13 @@
}
if (locale || o.locale) {
- if (language[0] != o.language[0]) {
- if (!language[0]) return false;
- if (!o.language[0]) return true;
+ const int diff = isLocaleMoreSpecificThan(o);
+ if (diff < 0) {
+ return false;
}
- if (country[0] != o.country[0]) {
- if (!country[0]) return false;
- if (!o.country[0]) return true;
+ if (diff > 0) {
+ return true;
}
}
@@ -1834,6 +1944,18 @@
}
}
+ if (localeScript[0] || o.localeScript[0]) {
+ if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) {
+ return localeScript[0];
+ }
+ }
+
+ if (localeVariant[0] || o.localeVariant[0]) {
+ if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) {
+ return localeVariant[0];
+ }
+ }
+
if (screenLayout || o.screenLayout) {
if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0
&& (requested->screenLayout & MASK_LAYOUTDIR)) {
@@ -2054,17 +2176,23 @@
}
}
if (locale != 0) {
+ // Don't consider the script & variants when deciding matches.
+ //
+ // If we two configs differ only in their script or language, they
+ // can be weeded out in the isMoreSpecificThan test.
if (language[0] != 0
&& (language[0] != settings.language[0]
|| language[1] != settings.language[1])) {
return false;
}
+
if (country[0] != 0
&& (country[0] != settings.country[0]
|| country[1] != settings.country[1])) {
return false;
}
}
+
if (screenConfig != 0) {
const int layoutDir = screenLayout&MASK_LAYOUTDIR;
const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR;
@@ -2166,17 +2294,92 @@
return true;
}
-void ResTable_config::getLocale(char str[6]) const {
- memset(str, 0, 6);
- if (language[0]) {
- str[0] = language[0];
- str[1] = language[1];
- if (country[0]) {
- str[2] = '_';
- str[3] = country[0];
- str[4] = country[1];
- }
+void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
+ memset(str, 0, RESTABLE_MAX_LOCALE_LEN);
+
+ // This represents the "any" locale value, which has traditionally been
+ // represented by the empty string.
+ if (!language[0] && !country[0]) {
+ return;
}
+
+ size_t charsWritten = 0;
+ if (language[0]) {
+ charsWritten += unpackLanguage(str);
+ }
+
+ if (localeScript[0]) {
+ if (charsWritten) {
+ str[charsWritten++] = '-';
+ }
+ memcpy(str + charsWritten, localeScript, sizeof(localeScript));
+ charsWritten += sizeof(localeScript);
+ }
+
+ if (country[0]) {
+ if (charsWritten) {
+ str[charsWritten++] = '-';
+ }
+ charsWritten += unpackRegion(str + charsWritten);
+ }
+
+ if (localeVariant[0]) {
+ if (charsWritten) {
+ str[charsWritten++] = '-';
+ }
+ memcpy(str + charsWritten, localeVariant, sizeof(localeVariant));
+ }
+}
+
+/* static */ inline bool assignLocaleComponent(ResTable_config* config,
+ const char* start, size_t size) {
+
+ switch (size) {
+ case 0:
+ return false;
+ case 2:
+ case 3:
+ config->language[0] ? config->packRegion(start) : config->packLanguage(start);
+ break;
+ case 4:
+ config->localeScript[0] = toupper(start[0]);
+ for (size_t i = 1; i < 4; ++i) {
+ config->localeScript[i] = tolower(start[i]);
+ }
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ for (size_t i = 0; i < size; ++i) {
+ config->localeVariant[i] = tolower(start[i]);
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+void ResTable_config::setBcp47Locale(const char* in) {
+ locale = 0;
+ memset(localeScript, 0, sizeof(localeScript));
+ memset(localeVariant, 0, sizeof(localeVariant));
+
+ const char* separator = in;
+ const char* start = in;
+ while ((separator = strchr(start, '-')) != NULL) {
+ const size_t size = separator - start;
+ if (!assignLocaleComponent(this, start, size)) {
+ fprintf(stderr, "Invalid BCP-47 locale string: %s", in);
+ }
+
+ start = (separator + 1);
+ }
+
+ const size_t size = in + strlen(in) - start;
+ assignLocaleComponent(this, start, size);
}
String8 ResTable_config::toString() const {
@@ -2190,14 +2393,10 @@
if (res.size() > 0) res.append("-");
res.appendFormat("%dmnc", dtohs(mnc));
}
- if (language[0] != 0) {
- if (res.size() > 0) res.append("-");
- res.append(language, 2);
- }
- if (country[0] != 0) {
- if (res.size() > 0) res.append("-");
- res.append(country, 2);
- }
+ char localeStr[RESTABLE_MAX_LOCALE_LEN];
+ getBcp47Locale(localeStr);
+ res.append(localeStr);
+
if ((screenLayout&MASK_LAYOUTDIR) != 0) {
if (res.size() > 0) res.append("-");
switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) {
@@ -4950,18 +5149,20 @@
const size_t L = type->configs.size();
for (size_t l=0; l<L; l++) {
const ResTable_type* config = type->configs[l];
- const ResTable_config* cfg = &config->config;
+ ResTable_config cfg;
+ memset(&cfg, 0, sizeof(ResTable_config));
+ cfg.copyFromDtoH(config->config);
// only insert unique
const size_t M = configs->size();
size_t m;
for (m=0; m<M; m++) {
- if (0 == (*configs)[m].compare(*cfg)) {
+ if (0 == (*configs)[m].compare(cfg)) {
break;
}
}
// if we didn't find it
if (m == M) {
- configs->add(*cfg);
+ configs->add(cfg);
}
}
}
@@ -4976,9 +5177,10 @@
getConfigurations(&configs);
ALOGV("called getConfigurations size=%d", (int)configs.size());
const size_t I = configs.size();
+
+ char locale[RESTABLE_MAX_LOCALE_LEN];
for (size_t i=0; i<I; i++) {
- char locale[6];
- configs[i].getLocale(locale);
+ configs[i].getBcp47Locale(locale);
const size_t J = locales->size();
size_t j;
for (j=0; j<J; j++) {
@@ -5601,9 +5803,9 @@
printf("mError=0x%x (%s)\n", mError, strerror(mError));
}
#if 0
- printf("mParams=%c%c-%c%c,\n",
- mParams.language[0], mParams.language[1],
- mParams.country[0], mParams.country[1]);
+ char localeStr[RESTABLE_MAX_LOCALE_LEN];
+ mParams.getBcp47Locale(localeStr);
+ printf("mParams=%s,\n" localeStr);
#endif
size_t pgCount = mPackageGroups.size();
printf("Package Groups (%d)\n", (int)pgCount);
@@ -5732,7 +5934,7 @@
continue;
}
- uint16_t esize = dtohs(ent->size);
+ uintptr_t esize = dtohs(ent->size);
if ((esize&0x3) != 0) {
printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
continue;
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 6e6522c..9e9649c 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -6,7 +6,8 @@
test_src_files := \
BackupData_test.cpp \
ObbFile_test.cpp \
- ZipUtils_test.cpp
+ ZipUtils_test.cpp \
+ ResourceTypes_test.cpp
shared_libraries := \
libandroidfw \
diff --git a/libs/androidfw/tests/ResourceTypes_test.cpp b/libs/androidfw/tests/ResourceTypes_test.cpp
new file mode 100644
index 0000000..4888b4a
--- /dev/null
+++ b/libs/androidfw/tests/ResourceTypes_test.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+namespace android {
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterLanguage) {
+ ResTable_config config;
+ config.packLanguage("en");
+
+ EXPECT_EQ('e', config.language[0]);
+ EXPECT_EQ('n', config.language[1]);
+
+ char out[4] = { 1, 1, 1, 1};
+ config.unpackLanguage(out);
+ EXPECT_EQ('e', out[0]);
+ EXPECT_EQ('n', out[1]);
+ EXPECT_EQ(0, out[2]);
+ EXPECT_EQ(0, out[3]);
+
+ memset(out, 1, sizeof(out));
+ config.locale = 0;
+ config.unpackLanguage(out);
+ EXPECT_EQ(0, out[0]);
+ EXPECT_EQ(0, out[1]);
+ EXPECT_EQ(0, out[2]);
+ EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterRegion) {
+ ResTable_config config;
+ config.packRegion("US");
+
+ EXPECT_EQ('U', config.country[0]);
+ EXPECT_EQ('S', config.country[1]);
+
+ char out[4] = { 1, 1, 1, 1};
+ config.unpackRegion(out);
+ EXPECT_EQ('U', out[0]);
+ EXPECT_EQ('S', out[1]);
+ EXPECT_EQ(0, out[2]);
+ EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguage) {
+ ResTable_config config;
+ config.packLanguage("eng");
+
+ // 1-00110-01 101-00100
+ EXPECT_EQ(0x99, config.language[0]);
+ EXPECT_EQ(0xa4, config.language[1]);
+
+ char out[4] = { 1, 1, 1, 1};
+ config.unpackLanguage(out);
+ EXPECT_EQ('e', out[0]);
+ EXPECT_EQ('n', out[1]);
+ EXPECT_EQ('g', out[2]);
+ EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterRegion) {
+ ResTable_config config;
+ config.packRegion("419");
+
+ char out[4] = { 1, 1, 1, 1};
+ config.unpackRegion(out);
+
+ EXPECT_EQ('4', out[0]);
+ EXPECT_EQ('1', out[1]);
+ EXPECT_EQ('9', out[2]);
+}
+
+/* static */ void fillIn(const char* lang, const char* country,
+ const char* script, const char* variant, ResTable_config* out) {
+ memset(out, 0, sizeof(ResTable_config));
+ if (lang != NULL) {
+ out->packLanguage(lang);
+ }
+
+ if (country != NULL) {
+ out->packRegion(country);
+ }
+
+ if (script != NULL) {
+ memcpy(out->localeScript, script, 4);
+ }
+
+ if (variant != NULL) {
+ memcpy(out->localeVariant, variant, strlen(variant));
+ }
+}
+
+TEST(ResourceTypesTest, IsMoreSpecificThan) {
+ ResTable_config l;
+ ResTable_config r;
+
+ fillIn("en", NULL, NULL, NULL, &l);
+ fillIn(NULL, NULL, NULL, NULL, &r);
+
+ EXPECT_TRUE(l.isMoreSpecificThan(r));
+ EXPECT_FALSE(r.isMoreSpecificThan(l));
+
+ fillIn("eng", NULL, NULL, NULL, &l);
+ EXPECT_TRUE(l.isMoreSpecificThan(r));
+ EXPECT_FALSE(r.isMoreSpecificThan(l));
+
+ fillIn("eng", "419", NULL, NULL, &r);
+ EXPECT_FALSE(l.isMoreSpecificThan(r));
+ EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+ fillIn("en", NULL, NULL, NULL, &l);
+ fillIn("en", "US", NULL, NULL, &r);
+ EXPECT_FALSE(l.isMoreSpecificThan(r));
+ EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+ fillIn("en", "US", NULL, NULL, &l);
+ fillIn("en", "US", "Latn", NULL, &r);
+ EXPECT_FALSE(l.isMoreSpecificThan(r));
+ EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+ fillIn("en", "US", NULL, NULL, &l);
+ fillIn("en", "US", NULL, "POSIX", &r);
+ EXPECT_FALSE(l.isMoreSpecificThan(r));
+ EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+ fillIn("en", "US", "Latn", NULL, &l);
+ fillIn("en", "US", NULL, "POSIX", &r);
+ EXPECT_FALSE(l.isMoreSpecificThan(r));
+ EXPECT_TRUE(r.isMoreSpecificThan(l));
+}
+
+TEST(ResourceTypesTest, setLocale) {
+ ResTable_config test;
+ test.setBcp47Locale("en-US");
+ EXPECT_EQ('e', test.language[0]);
+ EXPECT_EQ('n', test.language[1]);
+ EXPECT_EQ('U', test.country[0]);
+ EXPECT_EQ('S', test.country[1]);
+ EXPECT_EQ(0, test.localeScript[0]);
+ EXPECT_EQ(0, test.localeVariant[0]);
+
+ test.setBcp47Locale("eng-419");
+ char out[4] = { 1, 1, 1, 1};
+ test.unpackLanguage(out);
+ EXPECT_EQ('e', out[0]);
+ EXPECT_EQ('n', out[1]);
+ EXPECT_EQ('g', out[2]);
+ EXPECT_EQ(0, out[3]);
+ memset(out, 1, 4);
+ test.unpackRegion(out);
+ EXPECT_EQ('4', out[0]);
+ EXPECT_EQ('1', out[1]);
+ EXPECT_EQ('9', out[2]);
+
+
+ test.setBcp47Locale("en-Latn-419");
+ memset(out, 1, 4);
+ EXPECT_EQ('e', test.language[0]);
+ EXPECT_EQ('n', test.language[1]);
+
+ EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
+ test.unpackRegion(out);
+ EXPECT_EQ('4', out[0]);
+ EXPECT_EQ('1', out[1]);
+ EXPECT_EQ('9', out[2]);
+}
+
+} // namespace android.
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index e4648f6..8c388d9 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -39,7 +39,6 @@
RenderBufferCache.cpp \
ResourceCache.cpp \
ShadowTessellator.cpp \
- SkiaColorFilter.cpp \
SkiaShader.cpp \
Snapshot.cpp \
SpotShadow.cpp \
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 7eb7028..3d58964 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -224,6 +224,11 @@
if (op->getPaintAlpha() != mOps[0].op->getPaintAlpha()) return false;
+ if (op->mPaint && mOps[0].op->mPaint &&
+ op->mPaint->getColorFilter() != mOps[0].op->mPaint->getColorFilter()) {
+ return false;
+ }
+
/* Draw Modifiers compatibility check
*
* Shadows are ignored, as only text uses them, and in that case they are drawn
@@ -239,7 +244,6 @@
const DrawModifiers& lhsMod = lhs->mDrawModifiers;
const DrawModifiers& rhsMod = rhs->mDrawModifiers;
if (lhsMod.mShader != rhsMod.mShader) return false;
- if (lhsMod.mColorFilter != rhsMod.mColorFilter) return false;
// Draw filter testing expects bit fields to be clear if filter not set.
if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index fd3dae7..a5e66fa 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -96,10 +96,6 @@
caches.resourceCache.destructorLocked(bitmap);
}
- for (size_t i = 0; i < mFilterResources.size(); i++) {
- caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
- }
-
for (size_t i = 0; i < mPatchResources.size(); i++) {
caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
}
@@ -137,7 +133,6 @@
mBitmapResources.clear();
mOwnedBitmapResources.clear();
- mFilterResources.clear();
mPatchResources.clear();
mShaders.clear();
mSourcePaths.clear();
@@ -188,13 +183,6 @@
caches.resourceCache.incrementRefcountLocked(resource);
}
- const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
- for (size_t i = 0; i < filterResources.size(); i++) {
- SkiaColorFilter* resource = filterResources.itemAt(i);
- mFilterResources.add(resource);
- caches.resourceCache.incrementRefcountLocked(resource);
- }
-
const Vector<const Res_png_9patch*>& patchResources = recorder.getPatchResources();
for (size_t i = 0; i < patchResources.size(); i++) {
const Res_png_9patch* resource = patchResources.itemAt(i);
@@ -240,7 +228,11 @@
mClipToBounds = true;
mIsolatedZVolume = true;
mProjectBackwards = false;
+ mProjectionReceiver = false;
mOutline.rewind();
+ mClipToOutline = false;
+ mCastsShadow = false;
+ mSharesGlobalCamera = false;
mAlpha = 1;
mHasOverlappingRendering = true;
mTranslationX = 0;
@@ -299,12 +291,13 @@
void DisplayList::updateMatrix() {
if (mMatrixDirty) {
- if (!mTransformMatrix) {
- mTransformMatrix = new SkMatrix();
- }
- if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
- mTransformMatrix->reset();
- } else {
+ // NOTE: mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
+ // to a pure translate. This is safe because the matrix isn't read in pure translate cases.
+ if (mMatrixFlags && mMatrixFlags != TRANSLATION) {
+ if (!mTransformMatrix) {
+ // only allocate a matrix if we have a complex transform
+ mTransformMatrix = new Matrix4();
+ }
if (!mPivotExplicitlySet) {
if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
mPrevWidth = mWidth;
@@ -313,28 +306,36 @@
mPivotY = mPrevHeight / 2.0f;
}
}
- if (!Caches::getInstance().propertyEnable3d && (mMatrixFlags & ROTATION_3D) == 0) {
- mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
- mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
- mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ const bool perspectiveEnabled = Caches::getInstance().propertyEnable3d;
+ if (!perspectiveEnabled && (mMatrixFlags & ROTATION_3D) == 0) {
+ mTransformMatrix->loadTranslate(
+ mPivotX + mTranslationX,
+ mPivotY + mTranslationY,
+ 0);
+ mTransformMatrix->rotate(mRotation, 0, 0, 1);
+ mTransformMatrix->scale(mScaleX, mScaleY, 1);
+ mTransformMatrix->translate(-mPivotX, -mPivotY);
} else {
- if (Caches::getInstance().propertyEnable3d) {
- mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY,
+ if (perspectiveEnabled) {
+ mTransformMatrix->loadTranslate(
+ mPivotX + mTranslationX,
+ mPivotY + mTranslationY,
mTranslationZ);
- mTransform.rotate(mRotationX, 1, 0, 0);
- mTransform.rotate(mRotationY, 0, 1, 0);
- mTransform.rotate(mRotation, 0, 0, 1);
- mTransform.scale(mScaleX, mScaleY, 1);
- mTransform.translate(-mPivotX, -mPivotY);
+ mTransformMatrix->rotate(mRotationX, 1, 0, 0);
+ mTransformMatrix->rotate(mRotationY, 0, 1, 0);
+ mTransformMatrix->rotate(mRotation, 0, 0, 1);
+ mTransformMatrix->scale(mScaleX, mScaleY, 1);
+ mTransformMatrix->translate(-mPivotX, -mPivotY);
} else {
/* TODO: support this old transform approach, based on API level */
if (!mTransformCamera) {
mTransformCamera = new Sk3DView();
mTransformMatrix3D = new SkMatrix();
}
- mTransformMatrix->reset();
+ SkMatrix transformMatrix;
+ transformMatrix.reset();
mTransformCamera->save();
- mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ transformMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
mTransformCamera->rotateX(mRotationX);
mTransformCamera->rotateY(mRotationY);
mTransformCamera->rotateZ(-mRotation);
@@ -342,8 +343,10 @@
mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
mPivotY + mTranslationY);
- mTransformMatrix->postConcat(*mTransformMatrix3D);
+ transformMatrix.postConcat(*mTransformMatrix3D);
mTransformCamera->restore();
+
+ mTransformMatrix->load(transformMatrix);
}
}
}
@@ -357,19 +360,20 @@
ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
}
if (mStaticMatrix) {
- ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
- level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
+ ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
+ level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
}
if (mAnimationMatrix) {
- ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
- level * 2, "", mAnimationMatrix, MATRIX_ARGS(mAnimationMatrix));
+ ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
+ level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
}
if (mMatrixFlags != 0) {
if (mMatrixFlags == TRANSLATION) {
- ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
+ ALOGD("%*sTranslate %.2f, %.2f, %.2f",
+ level * 2, "", mTranslationX, mTranslationY, mTranslationZ);
} else {
- ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
- level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
+ ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING,
+ level * 2, "", mTransformMatrix, MATRIX_4_ARGS(mTransformMatrix));
}
}
@@ -419,19 +423,11 @@
renderer.concatMatrix(mAnimationMatrix);
}
if (mMatrixFlags != 0) {
- if (Caches::getInstance().propertyEnable3d) {
- if (mMatrixFlags == TRANSLATION) {
- renderer.translate(mTranslationX, mTranslationY, mTranslationZ);
- } else {
- renderer.concatMatrix(mTransform);
- }
+ if (mMatrixFlags == TRANSLATION) {
+ renderer.translate(mTranslationX, mTranslationY,
+ Caches::getInstance().propertyEnable3d ? mTranslationZ : 0.0f); // TODO: necessary?
} else {
- // avoid setting translationZ, use SkMatrix
- if (mMatrixFlags == TRANSLATION) {
- renderer.translate(mTranslationX, mTranslationY, 0);
- } else {
- renderer.concatMatrix(mTransformMatrix);
- }
+ renderer.concatMatrix(*mTransformMatrix);
}
}
bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
@@ -451,8 +447,7 @@
}
SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
- 0, 0, mRight - mLeft, mBottom - mTop,
- mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags);
+ 0, 0, mRight - mLeft, mBottom - mTop, mAlpha * 255, saveFlags);
handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
}
}
@@ -461,6 +456,10 @@
mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
}
+ if (CC_UNLIKELY(mClipToOutline && !mOutline.isEmpty())) {
+ ClipPathOp* op = new (handler.allocator()) ClipPathOp(&mOutline, SkRegion::kIntersect_Op);
+ handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
+ }
}
/**
@@ -482,12 +481,7 @@
if (mMatrixFlags == TRANSLATION) {
matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
} else {
- if (Caches::getInstance().propertyEnable3d) {
- matrix.multiply(mTransform);
- } else {
- mat4 temp(*mTransformMatrix);
- matrix.multiply(temp);
- }
+ matrix.multiply(*mTransformMatrix);
}
}
}
@@ -524,6 +518,7 @@
const mat4* transformFromProjectionSurface) {
m3dNodes.clear();
mProjectedNodes.clear();
+ if (mDisplayListData == NULL || mSize == 0) return;
// TODO: should avoid this calculation in most cases
// TODO: just calculate single matrix, down to all leaf composited elements
@@ -553,32 +548,46 @@
opState->mSkipInOrderDraw = false;
}
- if (mIsolatedZVolume) {
- // create a new 3d space for descendents by collecting them
- compositedChildrenOf3dRoot = &m3dNodes;
- transformFrom3dRoot = &mat4::identity();
- } else {
- applyViewPropertyTransforms(localTransformFrom3dRoot);
- transformFrom3dRoot = &localTransformFrom3dRoot;
- }
+ if (mDisplayListData->children.size() > 0) {
+ if (mIsolatedZVolume) {
+ // create a new 3d space for descendents by collecting them
+ compositedChildrenOf3dRoot = &m3dNodes;
+ transformFrom3dRoot = &mat4::identity();
+ } else {
+ applyViewPropertyTransforms(localTransformFrom3dRoot);
+ transformFrom3dRoot = &localTransformFrom3dRoot;
+ }
- if (mDisplayListData != NULL && mDisplayListData->projectionIndex >= 0) {
- // create a new projection surface for descendents by collecting them
- compositedChildrenOfProjectionSurface = &mProjectedNodes;
- transformFromProjectionSurface = &mat4::identity();
- } else {
- applyViewPropertyTransforms(localTransformFromProjectionSurface);
- transformFromProjectionSurface = &localTransformFromProjectionSurface;
- }
-
- if (mDisplayListData != NULL && mDisplayListData->children.size() > 0) {
+ const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
+ bool haveAppliedPropertiesToProjection = false;
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
- childOp->mDisplayList->computeOrderingImpl(childOp,
+ DisplayList* child = childOp->mDisplayList;
+
+ Vector<DrawDisplayListOp*>* projectionChildren = NULL;
+ const mat4* projectionTransform = NULL;
+ if (isProjectionReceiver && !child->mProjectBackwards) {
+ // if receiving projections, collect projecting descendent
+
+ // Note that if a direct descendent is projecting backwards, we pass it's
+ // grandparent projection collection, since it shouldn't project onto it's
+ // parent, where it will already be drawing.
+ projectionChildren = &mProjectedNodes;
+ projectionTransform = &mat4::identity();
+ } else {
+ if (!haveAppliedPropertiesToProjection) {
+ applyViewPropertyTransforms(localTransformFromProjectionSurface);
+ haveAppliedPropertiesToProjection = true;
+ }
+ projectionChildren = compositedChildrenOfProjectionSurface;
+ projectionTransform = &localTransformFromProjectionSurface;
+ }
+ child->computeOrderingImpl(childOp,
compositedChildrenOf3dRoot, transformFrom3dRoot,
- compositedChildrenOfProjectionSurface, transformFromProjectionSurface);
+ projectionChildren, projectionTransform);
}
}
+
}
class DeferOperationHandler {
@@ -638,11 +647,11 @@
return;
}
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
LinearAllocator& alloc = handler.allocator();
ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
SkRegion::kIntersect_Op); // clip to 3d root bounds for now
handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
- int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
for (size_t i = 0; i < m3dNodes.size(); i++) {
const float zValue = m3dNodes[i].key;
@@ -651,16 +660,13 @@
if (mode == kPositiveZChildren && zValue < 0.0f) continue;
if (mode == kNegativeZChildren && zValue > 0.0f) break;
- if (mode == kPositiveZChildren && zValue > 0.0f) {
+ DisplayList* child = childOp->mDisplayList;
+ if (mode == kPositiveZChildren && zValue > 0.0f && child->mCastsShadow) {
/* draw shadow with parent matrix applied, passing in the child's total matrix
- *
- * TODO:
- * -view must opt-in to shadows
- * -consider depth in more complex scenarios (neg z, added shadow depth)
+ * TODO: consider depth in more complex scenarios (neg z, added shadow depth)
*/
mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor);
- childOp->mDisplayList->applyViewPropertyTransforms(shadowMatrix);
- DisplayList* child = childOp->mDisplayList;
+ child->applyViewPropertyTransforms(shadowMatrix);
DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix,
child->mAlpha, &(child->mOutline), child->mWidth, child->mHeight);
@@ -677,18 +683,22 @@
template <class T>
void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
LinearAllocator& alloc = handler.allocator();
ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
SkRegion::kReplace_Op); // clip to projection surface root bounds
handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
- int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
for (size_t i = 0; i < mProjectedNodes.size(); i++) {
DrawDisplayListOp* childOp = mProjectedNodes[i];
+
+ // matrix save, concat, and restore can be done safely without allocating operations
+ int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
childOp->mSkipInOrderDraw = true;
+ renderer.restoreToCount(restoreTo);
}
handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
}
@@ -740,7 +750,7 @@
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionIndex = mDisplayListData->projectionIndex;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
DisplayListOp *op = mDisplayListData->displayListOps[i];
@@ -751,7 +761,7 @@
logBuffer.writeCommand(level, op->name());
handler(op, saveCountOffset, mClipToBounds);
- if (CC_UNLIKELY(i == projectionIndex && mProjectedNodes.size() > 0)) {
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
iterateProjectedChildren(renderer, handler, level);
}
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 8622d61..c3d9fd7 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -61,7 +61,6 @@
class OpenGLRenderer;
class Rect;
class Layer;
-class SkiaColorFilter;
class SkiaShader;
class ClipRectOp;
@@ -112,7 +111,7 @@
*/
class DisplayListData : public LightRefBase<DisplayListData> {
public:
- DisplayListData() : projectionIndex(-1) {}
+ DisplayListData() : projectionReceiveIndex(-1) {}
// allocator into which all ops were allocated
LinearAllocator allocator;
@@ -123,8 +122,7 @@
Vector<DrawDisplayListOp*> children;
// index of DisplayListOp restore, after which projected descendents should be drawn
- int projectionIndex;
- Matrix4 projectionTransform;
+ int projectionReceiveIndex;
};
/**
@@ -194,10 +192,26 @@
mIsolatedZVolume = shouldIsolate;
}
+ void setCastsShadow(bool castsShadow) {
+ mCastsShadow = castsShadow;
+ }
+
+ void setSharesGlobalCamera(bool sharesGlobalCamera) {
+ mSharesGlobalCamera = sharesGlobalCamera;
+ }
+
void setProjectBackwards(bool shouldProject) {
mProjectBackwards = shouldProject;
}
+ void setProjectionReceiver(bool shouldRecieve) {
+ mProjectionReceiver = shouldRecieve;
+ }
+
+ bool isProjectionReceiver() {
+ return mProjectionReceiver;
+ }
+
void setOutline(const SkPath* outline) {
if (!outline) {
mOutline.reset();
@@ -206,6 +220,10 @@
}
}
+ void setClipToOutline(bool clipToOutline) {
+ mClipToOutline = clipToOutline;
+ }
+
void setStaticMatrix(SkMatrix* matrix) {
delete mStaticMatrix;
mStaticMatrix = new SkMatrix(*matrix);
@@ -575,7 +593,6 @@
Vector<const SkBitmap*> mBitmapResources;
Vector<const SkBitmap*> mOwnedBitmapResources;
- Vector<SkiaColorFilter*> mFilterResources;
Vector<const Res_png_9patch*> mPatchResources;
Vector<const SkPaint*> mPaints;
@@ -600,7 +617,11 @@
bool mClipToBounds;
bool mIsolatedZVolume;
bool mProjectBackwards;
+ bool mProjectionReceiver;
SkPath mOutline;
+ bool mClipToOutline;
+ bool mCastsShadow;
+ bool mSharesGlobalCamera; // TODO: respect value when rendering
float mAlpha;
bool mHasOverlappingRendering;
float mTranslationX, mTranslationY, mTranslationZ;
@@ -614,13 +635,20 @@
bool mPivotExplicitlySet;
bool mMatrixDirty;
bool mMatrixIsIdentity;
+
+ /**
+ * Stores the total transformation of the DisplayList based upon its scalar
+ * translate/rotate/scale properties.
+ *
+ * In the common translation-only case, the matrix isn't allocated and the mTranslation
+ * properties are used directly.
+ */
+ Matrix4* mTransformMatrix;
uint32_t mMatrixFlags;
- SkMatrix* mTransformMatrix;
Sk3DView* mTransformCamera;
SkMatrix* mTransformMatrix3D;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
- Matrix4 mTransform;
bool mCaching;
/**
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 20bc93d..0589a02 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -327,9 +327,13 @@
class SaveLayerOp : public StateOp {
public:
- SaveLayerOp(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags)
- : mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
+ SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags)
+ : mArea(left, top, right, bottom), mPaint(&mCachedPaint), mFlags(flags) {
+ mCachedPaint.setAlpha(alpha);
+ }
+
+ SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags)
+ : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
bool useQuickReject) {
@@ -340,11 +344,11 @@
// NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
// setup the snapshot for deferral, and re-issue the op at flush time
deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
- mAlpha, mMode, mFlags);
+ mPaint, mFlags);
}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
+ renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mPaint, mFlags);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -357,21 +361,15 @@
int getFlags() { return mFlags; }
private:
- // Special case, reserved for direct DisplayList usage
- SaveLayerOp() {}
- DisplayListOp* reinit(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags) {
- mArea.set(left, top, right, bottom);
- mAlpha = alpha;
- mMode = mode;
- mFlags = flags;
- return this;
+ bool isSaveLayerAlpha() const {
+ SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
+ int alpha = OpenGLRenderer::getAlphaDirect(mPaint);
+ return alpha < 255 && mode == SkXfermode::kSrcOver_Mode;
}
- bool isSaveLayerAlpha() const { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
Rect mArea;
- int mAlpha;
- SkXfermode::Mode mMode;
+ const SkPaint* mPaint;
+ SkPaint mCachedPaint;
int mFlags;
};
@@ -465,7 +463,7 @@
virtual void output(int level, uint32_t logFlags) const {
if (mMatrix) {
- OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+ OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
} else {
OP_LOGS("SetMatrix (reset)");
}
@@ -487,7 +485,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+ OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
}
virtual const char* name() { return "ConcatMatrix"; }
@@ -622,38 +620,6 @@
SkiaShader* mShader;
};
-class ResetColorFilterOp : public StateOp {
-public:
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.resetColorFilter();
- }
-
- virtual void output(int level, uint32_t logFlags) const {
- OP_LOGS("ResetColorFilter");
- }
-
- virtual const char* name() { return "ResetColorFilter"; }
-};
-
-class SetupColorFilterOp : public StateOp {
-public:
- SetupColorFilterOp(SkiaColorFilter* colorFilter)
- : mColorFilter(colorFilter) {}
-
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.setupColorFilter(mColorFilter);
- }
-
- virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("SetupColorFilter, filter %p", mColorFilter);
- }
-
- virtual const char* name() { return "SetupColorFilter"; }
-
-private:
- SkiaColorFilter* mColorFilter;
-};
-
class ResetShadowOp : public StateOp {
public:
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
@@ -848,7 +814,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
+ OP_LOG("Draw bitmap %p matrix " SK_MATRIX_STRING, mBitmap, SK_MATRIX_ARGS(mMatrix));
}
virtual const char* name() { return "DrawBitmapMatrix"; }
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index c8a6c2d..0cbf088 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -53,10 +53,6 @@
mCaches.resourceCache.decrementRefcountLocked(mOwnedBitmapResources.itemAt(i));
}
- for (size_t i = 0; i < mFilterResources.size(); i++) {
- mCaches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
- }
-
for (size_t i = 0; i < mPatchResources.size(); i++) {
mCaches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
}
@@ -77,7 +73,6 @@
mBitmapResources.clear();
mOwnedBitmapResources.clear();
- mFilterResources.clear();
mPatchResources.clear();
mSourcePaths.clear();
@@ -173,17 +168,10 @@
StatefulBaseRenderer::restoreToCount(saveCount);
}
-void DisplayListRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
- bool restoreProjection = removed.flags & Snapshot::kFlagProjectionTarget;
- if (restoreProjection) {
- mDisplayListData->projectionIndex = mDisplayListData->displayListOps.size() - 1;
- mDisplayListData->projectionTransform.load(*currentTransform());
- }
-}
-
int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags) {
- addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags));
+ const SkPaint* paint, int flags) {
+ paint = refPaint(paint);
+ addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, flags));
return StatefulBaseRenderer::save(flags);
}
@@ -254,6 +242,9 @@
flags, *currentTransform());
addDrawOp(op);
mDisplayListData->children.push(op);
+ if (displayList->isProjectionReceiver()) {
+ mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
+ }
return DrawGlInfo::kStatusDone;
}
@@ -461,15 +452,6 @@
addStateOp(new (alloc()) SetupShaderOp(shader));
}
-void DisplayListRenderer::resetColorFilter() {
- addStateOp(new (alloc()) ResetColorFilterOp());
-}
-
-void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
- filter = refColorFilter(filter);
- addStateOp(new (alloc()) SetupColorFilterOp(filter));
-}
-
void DisplayListRenderer::resetShadow() {
addStateOp(new (alloc()) ResetShadowOp());
OpenGLRenderer::resetShadow();
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 1360808..7e62c5d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -82,7 +82,7 @@
virtual void restore();
virtual void restoreToCount(int saveCount);
virtual int saveLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags);
+ const SkPaint* paint, int flags);
// Matrix
virtual void translate(float dx, float dy, float dz);
@@ -102,9 +102,6 @@
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
- virtual void resetColorFilter();
- virtual void setupColorFilter(SkiaColorFilter* filter);
-
virtual void resetShadow();
virtual void setupShadow(float radius, float dx, float dy, int color);
@@ -182,10 +179,6 @@
return mOwnedBitmapResources;
}
- const Vector<SkiaColorFilter*>& getFilterResources() const {
- return mFilterResources;
- }
-
const Vector<const Res_png_9patch*>& getPatchResources() const {
return mPatchResources;
}
@@ -221,8 +214,6 @@
uint32_t getFunctorCount() const {
return mFunctorCount;
}
-protected:
- virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
private:
void insertRestoreToCount();
@@ -351,12 +342,6 @@
return shaderCopy;
}
- inline SkiaColorFilter* refColorFilter(SkiaColorFilter* colorFilter) {
- mFilterResources.add(colorFilter);
- mCaches.resourceCache.incrementRefcount(colorFilter);
- return colorFilter;
- }
-
inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
mPatchResources.add(patch);
mCaches.resourceCache.incrementRefcount(patch);
@@ -366,7 +351,6 @@
// TODO: move these to DisplayListData
Vector<const SkBitmap*> mBitmapResources;
Vector<const SkBitmap*> mOwnedBitmapResources;
- Vector<SkiaColorFilter*> mFilterResources;
Vector<const Res_png_9patch*> mPatchResources;
Vector<const SkPaint*> mPaints;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index f907d64..b79a3b0 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -72,9 +72,9 @@
break;
}
}
- renderer->setupDrawColorFilter();
+ renderer->setupDrawColorFilter(paint->getColorFilter());
renderer->setupDrawShader();
- renderer->setupDrawBlending(true, mode);
+ renderer->setupDrawBlending(paint);
renderer->setupDrawProgram();
renderer->setupDrawModelView(kModelViewMode_Translate, false,
0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
@@ -84,7 +84,7 @@
// needed
renderer->setupDrawTexture(0);
renderer->setupDrawPureColorUniforms();
- renderer->setupDrawColorFilterUniforms();
+ renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
renderer->setupDrawShaderUniforms(pureTranslate);
renderer->setupDrawTextGammaUniforms();
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 742ffd47..70eeb39 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -51,7 +51,7 @@
}
Layer::~Layer() {
- if (colorFilter) caches.resourceCache.decrementRefcount(colorFilter);
+ SkSafeUnref(colorFilter);
removeFbo();
deleteTexture();
@@ -135,14 +135,8 @@
OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
}
-void Layer::setColorFilter(SkiaColorFilter* filter) {
- if (colorFilter) {
- caches.resourceCache.decrementRefcount(colorFilter);
- }
- colorFilter = filter;
- if (colorFilter) {
- caches.resourceCache.incrementRefcount(colorFilter);
- }
+void Layer::setColorFilter(SkColorFilter* filter) {
+ SkRefCnt_SafeAssign(colorFilter, filter);
}
void Layer::bindTexture() const {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 471a4a6..ec80e9c 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_HWUI_LAYER_H
#define ANDROID_HWUI_LAYER_H
+#include <cutils/compiler.h>
#include <sys/types.h>
#include <GLES2/gl2.h>
@@ -26,9 +27,9 @@
#include <SkPaint.h>
#include <SkXfermode.h>
+#include "Matrix.h"
#include "Rect.h"
#include "RenderBuffer.h"
-#include "SkiaColorFilter.h"
#include "Texture.h"
#include "Vertex.h"
@@ -217,11 +218,11 @@
this->textureLayer = textureLayer;
}
- inline SkiaColorFilter* getColorFilter() const {
+ inline SkColorFilter* getColorFilter() const {
return colorFilter;
}
- ANDROID_API void setColorFilter(SkiaColorFilter* filter);
+ ANDROID_API void setColorFilter(SkColorFilter* filter);
void bindStencilRenderBuffer() const;
@@ -339,7 +340,7 @@
/**
* Color filter used to draw this layer. Optional.
*/
- SkiaColorFilter* colorFilter;
+ SkColorFilter* colorFilter;
/**
* Opacity of the layer.
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 00ca050..5cd79b1 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -26,12 +26,20 @@
namespace android {
namespace uirenderer {
-#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
-#define MATRIX_ARGS(m) \
+#define SK_MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
+#define SK_MATRIX_ARGS(m) \
(m)->get(0), (m)->get(1), (m)->get(2), \
(m)->get(3), (m)->get(4), (m)->get(5), \
(m)->get(6), (m)->get(7), (m)->get(8)
+#define MATRIX_4_STRING "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
+ " [%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]"
+#define MATRIX_4_ARGS(m) \
+ (m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], \
+ (m)->data[1], (m)->data[5], (m)->data[9], (m)->data[13], \
+ (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
+ (m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15] \
+
///////////////////////////////////////////////////////////////////////////////
// Classes
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b710825..fee916b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -731,11 +731,11 @@
///////////////////////////////////////////////////////////////////////////////
int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags) {
+ const SkPaint* paint, int flags) {
const int count = saveSnapshot(flags);
if (!currentSnapshot()->isIgnored()) {
- createLayer(left, top, right, bottom, alpha, mode, flags);
+ createLayer(left, top, right, bottom, paint, flags);
}
return count;
@@ -786,7 +786,7 @@
}
int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags) {
+ const SkPaint* paint, int flags) {
const int count = saveSnapshot(flags);
if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
@@ -797,7 +797,7 @@
Rect bounds(left, top, right, bottom);
Rect clip;
calculateLayerBoundsAndClip(bounds, clip, true);
- updateSnapshotIgnoreForLayer(bounds, clip, true, alpha);
+ updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
if (!currentSnapshot()->isIgnored()) {
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
@@ -862,12 +862,15 @@
* something actually gets drawn are the layers regions cleared.
*/
bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags) {
+ const SkPaint* paint, int flags) {
LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
+ SkXfermode::Mode mode = getXfermodeDirect(paint);
+ int alpha = getAlphaDirect(paint);
+
// Window coordinates of the layer
Rect clip;
Rect bounds(left, top, right, bottom);
@@ -889,7 +892,8 @@
layer->layer.set(bounds);
layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
bounds.getWidth() / float(layer->getWidth()), 0.0f);
- layer->setColorFilter(mDrawModifiers.mColorFilter);
+
+ layer->setColorFilter(getColorFilter(paint));
layer->setBlend(true);
layer->setDirty(false);
@@ -1007,8 +1011,13 @@
}
if (!fboLayer && layer->getAlpha() < 255) {
- drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
- layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
+ // TODO: this seems to point to the fact that the layer should store the paint
+ SkPaint layerPaint;
+ layerPaint.setAlpha(layer->getAlpha());
+ layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+ layerPaint.setColorFilter(layer->getColorFilter());
+
+ drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
// Required below, composeLayerRect() will divide by 255
layer->setAlpha(255);
}
@@ -1021,13 +1030,7 @@
// drawing only the dirty region
if (fboLayer) {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
- if (layer->getColorFilter()) {
- setupColorFilter(layer->getColorFilter());
- }
composeLayerRegion(layer, rect);
- if (layer->getColorFilter()) {
- resetColorFilter();
- }
} else if (!rect.isEmpty()) {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
@@ -1059,11 +1062,11 @@
}
setupDrawTextureTransform();
setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter();
- setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
+ setupDrawColorFilter(layer->getColorFilter());
+ setupDrawBlending(layer);
setupDrawProgram();
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(layer->getColorFilter());
if (layer->getRenderTarget() == GL_TEXTURE_2D) {
setupDrawTexture(layer->getTexture());
} else {
@@ -1113,10 +1116,14 @@
layer->setFilter(GL_LINEAR, true);
}
- float alpha = getLayerAlpha(layer);
- bool blend = layer->isBlend() || alpha < 1.0f;
+ SkPaint layerPaint;
+ layerPaint.setAlpha(getLayerAlpha(layer) * 255);
+ layerPaint.setXfermodeMode(layer->getMode());
+ layerPaint.setColorFilter(layer->getColorFilter());
+
+ bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
- layer->getTexture(), alpha, layer->getMode(), blend,
+ layer->getTexture(), &layerPaint, blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
@@ -1181,12 +1188,12 @@
setupDrawWithTexture();
setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter();
- setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
+ setupDrawColorFilter(layer->getColorFilter());
+ setupDrawBlending(layer);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(layer->getColorFilter());
setupDrawTexture(layer->getTexture());
if (currentTransform()->isPureTranslate()) {
const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
@@ -1258,15 +1265,15 @@
top = rects[i].top;
}
+ SkPaint paint;
+ paint.setColor(colors[offset + (i & 0x1)]);
Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
- drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
- SkXfermode::kSrcOver_Mode);
+ drawColorRect(r.left, r.top, r.right, r.bottom, paint);
}
}
#endif
-void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color,
- SkXfermode::Mode mode, bool dirty) {
+void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
Vector<float> rects;
SkRegion::Iterator it(region);
@@ -1279,7 +1286,7 @@
it.next();
}
- drawColorRects(rects.array(), rects.size(), color, mode, true, dirty, false);
+ drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
}
void OpenGLRenderer::dirtyLayer(const float left, const float top,
@@ -1356,9 +1363,12 @@
// the same thing again
mLayers.clear();
+ SkPaint clearPaint;
+ clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
+
setupDraw(false);
setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
- setupDrawBlending(true, SkXfermode::kClear_Mode);
+ setupDrawBlending(&clearPaint, true);
setupDrawProgram();
setupDrawPureColorUniforms();
setupDrawModelView(kModelViewMode_Translate, false,
@@ -1517,22 +1527,26 @@
mCaches.stencil.clear();
if (resetScissor) mCaches.disableScissor();
+ SkPaint paint;
+ paint.setColor(0xff000000);
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+
// NOTE: We could use the region contour path to generate a smaller mesh
// Since we are using the stencil we could use the red book path
// drawing technique. It might increase bandwidth usage though.
// The last parameter is important: we are not drawing in the color buffer
// so we don't want to dirty the current layer, if any
- drawRegionRects(*(currentSnapshot()->clipRegion),
- 0xff000000, SkXfermode::kSrc_Mode, false);
+ drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
mCaches.stencil.enableTest();
// Draw the region used to generate the stencil if the appropriate debug
// mode is enabled
if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
- drawRegionRects(*(currentSnapshot()->clipRegion),
- 0x7f0000ff, SkXfermode::kSrcOver_Mode);
+ paint.setColor(0x7f0000ff);
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ drawRegionRects(*(currentSnapshot()->clipRegion), paint);
}
} else {
mCaches.stencil.disable();
@@ -1573,7 +1587,10 @@
void OpenGLRenderer::debugClip() {
#if DEBUG_CLIP_REGIONS
if (!isRecording() && !currentSnapshot()->clipRegion->isEmpty()) {
- drawRegionRects(*(currentSnapshot()->clipRegion), 0x7f00ff00, SkXfermode::kSrcOver_Mode);
+ SkPaint paint;
+ paint.setColor(0x7f00ff00);
+ drawRegionRects(*(currentSnapshot()->clipRegion, paint);
+
}
#endif
}
@@ -1672,9 +1689,17 @@
}
}
-void OpenGLRenderer::setupDrawColorFilter() {
- if (mDrawModifiers.mColorFilter) {
- mDrawModifiers.mColorFilter->describe(mDescription, mExtensions);
+void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
+ if (filter == NULL) {
+ return;
+ }
+
+ SkXfermode::Mode mode;
+ if (filter->asColorMode(NULL, &mode)) {
+ mDescription.colorOp = ProgramDescription::kColorBlend;
+ mDescription.colorMode = mode;
+ } else if (filter->asColorMatrix(NULL)) {
+ mDescription.colorOp = ProgramDescription::kColorMatrix;
}
}
@@ -1686,22 +1711,26 @@
}
}
-void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
+void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
+ SkXfermode::Mode mode = layer->getMode();
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
- bool blend = (mColorSet && mColorA < 1.0f) ||
- (mDrawModifiers.mShader && mDrawModifiers.mShader->blend());
+ bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
+ (mColorSet && mColorA < 1.0f) ||
+ (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
+ layer->getColorFilter();
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
-void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
+void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
+ SkXfermode::Mode mode = getXfermodeDirect(paint);
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
blend |= (mColorSet && mColorA < 1.0f) ||
(mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
- (mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend());
+ (paint && paint->getColorFilter());
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
@@ -1758,10 +1787,47 @@
}
}
-void OpenGLRenderer::setupDrawColorFilterUniforms() {
- if (mDrawModifiers.mColorFilter) {
- mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
+void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
+ if (NULL == filter) {
+ return;
}
+
+ SkColor color;
+ SkXfermode::Mode mode;
+ if (filter->asColorMode(&color, &mode)) {
+ const int alpha = SkColorGetA(color);
+ const GLfloat a = alpha / 255.0f;
+ const GLfloat r = a * SkColorGetR(color) / 255.0f;
+ const GLfloat g = a * SkColorGetG(color) / 255.0f;
+ const GLfloat b = a * SkColorGetB(color) / 255.0f;
+ glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
+ return;
+ }
+
+ SkScalar srcColorMatrix[20];
+ if (filter->asColorMatrix(srcColorMatrix)) {
+
+ float colorMatrix[16];
+ memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
+ memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
+ memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
+ memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
+
+ // Skia uses the range [0..255] for the addition vector, but we need
+ // the [0..1] range to apply the vector in GLSL
+ float colorVector[4];
+ colorVector[0] = srcColorMatrix[4] / 255.0f;
+ colorVector[1] = srcColorMatrix[9] / 255.0f;
+ colorVector[2] = srcColorMatrix[14] / 255.0f;
+ colorVector[3] = srcColorMatrix[19] / 255.0f;
+
+ glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
+ GL_FALSE, colorMatrix);
+ glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
+ return;
+ }
+
+ // it is an error if we ever get here
}
void OpenGLRenderer::setupDrawTextGammaUniforms() {
@@ -1896,10 +1962,6 @@
}
void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
- int alpha;
- SkXfermode::Mode mode;
- getAlphaAndMode(paint, &alpha, &mode);
-
int color = paint != NULL ? paint->getColor() : 0;
float x = left;
@@ -1921,7 +1983,7 @@
// No need to check for a UV mapper on the texture object, only ARGB_8888
// bitmaps get packed in the atlas
drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
- paint != NULL, color, alpha, mode, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
+ paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
}
@@ -1939,26 +2001,19 @@
const AutoTexture autoCleanup(texture);
- int alpha;
- SkXfermode::Mode mode;
- getAlphaAndMode(paint, &alpha, &mode);
-
texture->setWrap(GL_CLAMP_TO_EDGE, true);
texture->setFilter(pureTranslate ? GL_NEAREST : FILTER(paint), true);
const float x = (int) floorf(bounds.left + 0.5f);
const float y = (int) floorf(bounds.top + 0.5f);
if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
- int color = paint != NULL ? paint->getColor() : 0;
drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
- texture->id, paint != NULL, color, alpha, mode,
- &vertices[0].x, &vertices[0].u,
+ texture->id, paint, &vertices[0].x, &vertices[0].u,
GL_TRIANGLES, bitmapCount * 6, true,
kModelViewMode_Translate, false);
} else {
drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
- texture->id, alpha / 255.0f, mode, texture->blend,
- &vertices[0].x, &vertices[0].u,
+ texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
GL_TRIANGLES, bitmapCount * 6, false, true, 0,
kModelViewMode_Translate, false);
}
@@ -2138,14 +2193,14 @@
setupDraw();
setupDrawWithTextureAndColor();
setupDrawColor(a, a, a, a);
- setupDrawColorFilter();
- setupDrawBlending(true, mode, false);
+ setupDrawColorFilter(getColorFilter(paint));
+ setupDrawBlending(paint, true);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
setupDrawTexture(texture->id);
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
glDrawArrays(GL_TRIANGLES, 0, count);
@@ -2186,10 +2241,6 @@
mCaches.unbindMeshBuffer();
resetDrawTextureTexCoords(u1, v1, u2, v2);
- int alpha;
- SkXfermode::Mode mode;
- getAlphaAndMode(paint, &alpha, &mode);
-
texture->setWrap(GL_CLAMP_TO_EDGE, true);
float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
@@ -2231,14 +2282,13 @@
}
if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
- int color = paint ? paint->getColor() : 0;
drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
- texture->id, paint != NULL, color, alpha, mode,
+ texture->id, paint,
&mMeshVertices[0].x, &mMeshVertices[0].u,
GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
} else {
drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
- texture->id, alpha / 255.0f, mode, texture->blend,
+ texture->id, paint, texture->blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
}
@@ -2281,10 +2331,6 @@
texture->setWrap(GL_CLAMP_TO_EDGE, true);
texture->setFilter(GL_LINEAR, true);
- int alpha;
- SkXfermode::Mode mode;
- getAlphaAndMode(paint, &alpha, &mode);
-
const bool pureTranslate = currentTransform()->isPureTranslate();
// Mark the current layer dirty where we are going to draw the patch
if (hasLayer() && mesh->hasEmptyQuads) {
@@ -2315,8 +2361,8 @@
top = y;
ignoreTransform = true;
}
- drawIndexedTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
- mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
+ drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
+ texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
}
@@ -2339,12 +2385,8 @@
texture->setWrap(GL_CLAMP_TO_EDGE, true);
texture->setFilter(GL_LINEAR, true);
- int alpha;
- SkXfermode::Mode mode;
- getAlphaAndMode(paint, &alpha, &mode);
-
- drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
- mode, texture->blend, &vertices[0].x, &vertices[0].u,
+ drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
+ texture->blend, &vertices[0].x, &vertices[0].u,
GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
return DrawGlInfo::kStatusDrew;
@@ -2360,20 +2402,19 @@
}
int color = paint->getColor();
- SkXfermode::Mode mode = getXfermode(paint->getXfermode());
bool isAA = paint->isAntiAlias();
setupDraw();
setupDrawNoTexture();
if (isAA) setupDrawAA();
setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
- setupDrawColorFilter();
+ setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
- setupDrawBlending(isAA, mode);
+ setupDrawBlending(paint, isAA);
setupDrawProgram();
setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0);
setupDrawColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms();
const void* vertices = vertexBuffer.getBuffer();
@@ -2482,7 +2523,11 @@
Rect clip(*currentClipRect());
clip.snapToPixelBoundaries();
- drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setXfermodeMode(mode);
+
+ drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
return DrawGlInfo::kStatusDrew;
}
@@ -2638,14 +2683,14 @@
path.addRect(left, top, right, bottom);
return drawConvexPath(path, p);
} else {
- drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode()));
+ drawColorRect(left, top, right, bottom, p);
return DrawGlInfo::kStatusDrew;
}
}
void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
int bytesCount, int count, const float* positions,
- FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, float x, float y) {
+ FontRenderer& fontRenderer, int alpha, float x, float y) {
mCaches.activeTexture(0);
// NOTE: The drop shadow will not perform gamma correction
@@ -2670,15 +2715,15 @@
setupDraw();
setupDrawWithTexture(true);
setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
- setupDrawColorFilter();
+ setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
- setupDrawBlending(true, mode);
+ setupDrawBlending(paint, true);
setupDrawProgram();
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
sx, sy, sx + shadow->width, sy + shadow->height);
setupDrawTexture(shadow->id);
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms();
setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
@@ -2720,7 +2765,7 @@
if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
- alpha, mode, 0.0f, 0.0f);
+ alpha, 0.0f, 0.0f);
}
// Pick the appropriate texture filtering
@@ -2798,7 +2843,7 @@
if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
fontRenderer.setFont(paint, mat4::identity());
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
- alpha, mode, oldX, oldY);
+ alpha, oldX, oldY);
}
const bool hasActiveLayer = hasLayer();
@@ -2934,22 +2979,20 @@
mCaches.activeTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
- SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter;
- mDrawModifiers.mColorFilter = layer->getColorFilter();
-
if (layer->region.isRect()) {
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
composeLayerRect(layer, layer->regionRect));
} else if (layer->mesh) {
+
const float a = getLayerAlpha(layer);
setupDraw();
setupDrawWithTexture();
setupDrawColor(a, a, a, a);
- setupDrawColorFilter();
- setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
+ setupDrawColorFilter(layer->getColorFilter());
+ setupDrawBlending(layer);
setupDrawProgram();
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(layer->getColorFilter());
setupDrawTexture(layer->getTexture());
if (CC_LIKELY(currentTransform()->isPureTranslate())) {
int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
@@ -2985,12 +3028,12 @@
#endif
}
- mDrawModifiers.mColorFilter = oldFilter;
-
if (layer->debugDrawUpdate) {
layer->debugDrawUpdate = false;
- drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
- 0x7f00ff00, SkXfermode::kSrcOver_Mode);
+
+ SkPaint paint;
+ paint.setColor(0x7f00ff00);
+ drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
}
}
layer->hasDrawnSinceUpdate = true;
@@ -3018,18 +3061,6 @@
}
///////////////////////////////////////////////////////////////////////////////
-// Color filters
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetColorFilter() {
- mDrawModifiers.mColorFilter = NULL;
-}
-
-void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
- mDrawModifiers.mColorFilter = filter;
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Drop shadow
///////////////////////////////////////////////////////////////////////////////
@@ -3102,15 +3133,15 @@
setupDraw();
setupDrawWithTexture(true);
setupDrawAlpha8Color(paint->getColor(), alpha);
- setupDrawColorFilter();
+ setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
- setupDrawBlending(true, mode);
+ setupDrawBlending(paint, true);
setupDrawProgram();
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
x, y, x + texture->width, y + texture->height);
setupDrawTexture(texture->id);
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms();
setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
@@ -3172,14 +3203,7 @@
return DrawGlInfo::kStatusDone;
}
- int color = paint->getColor();
- // If a shader is set, preserve only the alpha
- if (mDrawModifiers.mShader) {
- color |= 0x00ffffff;
- }
- SkXfermode::Mode mode = getXfermode(paint->getXfermode());
-
- return drawColorRects(rects, count, color, mode);
+ return drawColorRects(rects, count, paint, false, true, true);
}
status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha,
@@ -3231,12 +3255,18 @@
return DrawGlInfo::kStatusDrew;
}
-status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
- SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) {
+status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
+ bool ignoreTransform, bool dirty, bool clip) {
if (count == 0) {
return DrawGlInfo::kStatusDone;
}
+ int color = paint->getColor();
+ // If a shader is set, preserve only the alpha
+ if (mDrawModifiers.mShader) {
+ color |= 0x00ffffff;
+ }
+
float left = FLT_MAX;
float top = FLT_MAX;
float right = FLT_MIN;
@@ -3270,15 +3300,15 @@
setupDrawNoTexture();
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
setupDrawShader();
- setupDrawColorFilter();
- setupDrawBlending(mode);
+ setupDrawColorFilter(getColorFilter(paint));
+ setupDrawBlending(paint);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawModelView(kModelViewMode_Translate, false,
0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
setupDrawColorUniforms();
setupDrawShaderUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
if (dirty && hasLayer()) {
dirtyLayer(left, top, right, bottom, *currentTransform());
@@ -3290,7 +3320,8 @@
}
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
- int color, SkXfermode::Mode mode, bool ignoreTransform) {
+ const SkPaint* paint, bool ignoreTransform) {
+ int color = paint->getColor();
// If a shader is set, preserve only the alpha
if (mDrawModifiers.mShader) {
color |= 0x00ffffff;
@@ -3300,14 +3331,14 @@
setupDrawNoTexture();
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
setupDrawShader();
- setupDrawColorFilter();
- setupDrawBlending(mode);
+ setupDrawColorFilter(getColorFilter(paint));
+ setupDrawBlending(paint);
setupDrawProgram();
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
left, top, right, bottom, ignoreTransform);
setupDrawColorUniforms();
setupDrawShaderUniforms(ignoreTransform);
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawSimpleMesh();
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -3315,10 +3346,6 @@
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
Texture* texture, const SkPaint* paint) {
- int alpha;
- SkXfermode::Mode mode;
- getAlphaAndMode(paint, &alpha, &mode);
-
texture->setWrap(GL_CLAMP_TO_EDGE, true);
GLvoid* vertices = (GLvoid*) NULL;
@@ -3340,11 +3367,11 @@
texture->setFilter(GL_NEAREST, true);
drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
- alpha / 255.0f, mode, texture->blend, vertices, texCoords,
+ paint, texture->blend, vertices, texCoords,
GL_TRIANGLE_STRIP, gMeshCount, false, true);
} else {
texture->setFilter(FILTER(paint), true);
- drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
+ drawTextureMesh(left, top, right, bottom, texture->id, paint,
texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
}
@@ -3353,75 +3380,84 @@
}
}
-void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
- GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
- drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
- (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount);
-}
-
void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
- GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
+ GLuint texture, const SkPaint* paint, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool swapSrcDst, bool ignoreTransform, GLuint vbo,
ModelViewMode modelViewMode, bool dirty) {
+ int a;
+ SkXfermode::Mode mode;
+ getAlphaAndMode(paint, &a, &mode);
+ const float alpha = a / 255.0f;
+
setupDraw();
setupDrawWithTexture();
setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter();
- setupDrawBlending(blend, mode, swapSrcDst);
+ setupDrawColorFilter(getColorFilter(paint));
+ setupDrawBlending(paint, blend, swapSrcDst);
setupDrawProgram();
if (!dirty) setupDrawDirtyRegionsDisabled();
setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
setupDrawTexture(texture);
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawMesh(vertices, texCoords, vbo);
glDrawArrays(drawMode, 0, elementsCount);
}
void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
- GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
+ GLuint texture, const SkPaint* paint, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool swapSrcDst, bool ignoreTransform, GLuint vbo,
ModelViewMode modelViewMode, bool dirty) {
+ int a;
+ SkXfermode::Mode mode;
+ getAlphaAndMode(paint, &a, &mode);
+ const float alpha = a / 255.0f;
+
setupDraw();
setupDrawWithTexture();
setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter();
- setupDrawBlending(blend, mode, swapSrcDst);
+ setupDrawColorFilter(getColorFilter(paint));
+ setupDrawBlending(paint, blend, swapSrcDst);
setupDrawProgram();
if (!dirty) setupDrawDirtyRegionsDisabled();
setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
setupDrawTexture(texture);
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawMeshIndices(vertices, texCoords, vbo);
glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
}
void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
- GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
+ GLuint texture, const SkPaint* paint,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
+ int color = paint != NULL ? paint->getColor() : 0;
+ int alpha;
+ SkXfermode::Mode mode;
+ getAlphaAndMode(paint, &alpha, &mode);
+
setupDraw();
setupDrawWithTexture(true);
- if (hasColor) {
+ if (paint != NULL) {
setupDrawAlpha8Color(color, alpha);
}
- setupDrawColorFilter();
+ setupDrawColorFilter(getColorFilter(paint));
setupDrawShader();
- setupDrawBlending(true, mode);
+ setupDrawBlending(paint, true);
setupDrawProgram();
if (!dirty) setupDrawDirtyRegionsDisabled();
setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
setupDrawTexture(texture);
setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms();
+ setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms(ignoreTransform);
setupDrawMesh(vertices, texCoords);
@@ -3512,7 +3548,7 @@
*alpha *= currentSnapshot()->alpha;
}
-float OpenGLRenderer::getLayerAlpha(Layer* layer) const {
+float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
float alpha;
if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
alpha = mDrawModifiers.mOverrideLayerAlpha;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index c8ecdda..e4d133d 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -21,6 +21,8 @@
#include <GLES2/gl2ext.h>
#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkColorFilter.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkRegion.h>
@@ -43,7 +45,6 @@
#include "Rect.h"
#include "Renderer.h"
#include "StatefulBaseRenderer.h"
-#include "SkiaColorFilter.h"
#include "Snapshot.h"
#include "UvMapper.h"
#include "Vertex.h"
@@ -68,7 +69,6 @@
}
SkiaShader* mShader;
- SkiaColorFilter* mColorFilter;
float mOverrideLayerAlpha;
// Drop shadow
@@ -154,21 +154,11 @@
ANDROID_API void clearLayerUpdates();
ANDROID_API void flushLayerUpdates();
- ANDROID_API int saveLayer(float left, float top, float right, float bottom,
- SkPaint* paint, int flags) {
- SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
- if (paint) mode = getXfermode(paint->getXfermode());
- return saveLayer(left, top, right, bottom, paint ? paint->getAlpha() : 255, mode, flags);
- }
- ANDROID_API int saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, int flags) {
- return saveLayer(left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
- }
- virtual int saveLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags);
+ ANDROID_API virtual int saveLayer(float left, float top, float right, float bottom,
+ const SkPaint* paint, int flags);
int saveLayerDeferred(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags);
+ const SkPaint* paint, int flags);
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags = 1);
virtual status_t drawLayer(Layer* layer, float x, float y);
@@ -219,9 +209,6 @@
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
- virtual void resetColorFilter();
- virtual void setupColorFilter(SkiaColorFilter* filter);
-
virtual void resetShadow();
virtual void setupShadow(float radius, float dx, float dy, int color);
@@ -442,18 +429,14 @@
*
* @param layer The layer from which the alpha is extracted
*/
- inline float getLayerAlpha(Layer* layer) const;
+ inline float getLayerAlpha(const Layer* layer) const;
/**
- * Safely retrieves the mode from the specified xfermode. If the specified
- * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
+ * Safely retrieves the ColorFilter from the given Paint. If the paint is
+ * null then null is returned.
*/
- static inline SkXfermode::Mode getXfermode(SkXfermode* mode) {
- SkXfermode::Mode resultMode;
- if (!SkXfermode::AsMode(mode, &resultMode)) {
- resultMode = SkXfermode::kSrcOver_Mode;
- }
- return resultMode;
+ static inline SkColorFilter* getColorFilter(const SkPaint* paint) {
+ return paint ? paint->getColorFilter() : NULL;
}
/**
@@ -538,7 +521,7 @@
* @return True if the layer was successfully created, false otherwise
*/
bool createLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags);
+ const SkPaint* paint, int flags);
/**
* Creates a new layer stored in the specified snapshot as an FBO.
@@ -594,12 +577,11 @@
* @param top The top coordinate of the rectangle
* @param right The right coordinate of the rectangle
* @param bottom The bottom coordinate of the rectangle
- * @param color The rectangle's ARGB color, defined as a packed 32 bits word
- * @param mode The Skia xfermode to use
+ * @param paint The paint containing the color, blending mode, etc.
* @param ignoreTransform True if the current transform should be ignored
*/
void drawColorRect(float left, float top, float right, float bottom,
- int color, SkXfermode::Mode mode, bool ignoreTransform = false);
+ const SkPaint* paint, bool ignoreTransform = false);
/**
* Draws a series of colored rectangles with the specified color. The specified
@@ -608,15 +590,13 @@
*
* @param rects A list of rectangles, 4 floats (left, top, right, bottom)
* per rectangle
- * @param color The rectangles' ARGB color, defined as a packed 32 bits word
- * @param mode The Skia xfermode to use
+ * @param paint The paint containing the color, blending mode, etc.
* @param ignoreTransform True if the current transform should be ignored
* @param dirty True if calling this method should dirty the current layer
* @param clip True if the rects should be clipped, false otherwise
*/
- status_t drawColorRects(const float* rects, int count, int color,
- SkXfermode::Mode mode, bool ignoreTransform = false,
- bool dirty = true, bool clip = true);
+ status_t drawColorRects(const float* rects, int count, const SkPaint* paint,
+ bool ignoreTransform = false, bool dirty = true, bool clip = true);
/**
* Draws the shape represented by the specified path texture.
@@ -668,22 +648,6 @@
* @param top The top coordinate of the rectangle
* @param right The right coordinate of the rectangle
* @param bottom The bottom coordinate of the rectangle
- * @param texture The texture name to map onto the rectangle
- * @param alpha An additional translucency parameter, between 0.0f and 1.0f
- * @param mode The blending mode
- * @param blend True if the texture contains an alpha channel
- */
- void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
- float alpha, SkXfermode::Mode mode, bool blend);
-
- /**
- * Draws a textured rectangle with the specified texture. The specified coordinates
- * are transformed by the current snapshot's transform matrix.
- *
- * @param left The left coordinate of the rectangle
- * @param top The top coordinate of the rectangle
- * @param right The right coordinate of the rectangle
- * @param bottom The bottom coordinate of the rectangle
* @param texture The texture to use
* @param paint The paint containing the alpha, blending mode, etc.
*/
@@ -700,8 +664,7 @@
* @param right The right coordinate of the rectangle
* @param bottom The bottom coordinate of the rectangle
* @param texture The texture name to map onto the rectangle
- * @param alpha An additional translucency parameter, between 0.0f and 1.0f
- * @param mode The blending mode
+ * @param paint The paint containing the alpha, blending mode, colorFilter, etc.
* @param blend True if the texture contains an alpha channel
* @param vertices The vertices that define the mesh
* @param texCoords The texture coordinates of each vertex
@@ -713,19 +676,19 @@
* @param dirty True if calling this method should dirty the current layer
*/
void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
- float alpha, SkXfermode::Mode mode, bool blend,
+ const SkPaint* paint, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
void drawIndexedTextureMesh(float left, float top, float right, float bottom, GLuint texture,
- float alpha, SkXfermode::Mode mode, bool blend,
+ const SkPaint* paint, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
- GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
+ GLuint texture, const SkPaint* paint,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool ignoreTransform, ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale,
bool dirty = true);
@@ -759,12 +722,11 @@
* @param positions The x, y positions of individual glyphs (or NULL)
* @param fontRenderer The font renderer object
* @param alpha The alpha value for drawing the shadow
- * @param mode The xfermode for drawing the shadow
* @param x The x coordinate where the shadow will be drawn
* @param y The y coordinate where the shadow will be drawn
*/
void drawTextShadow(const SkPaint* paint, const char* text, int bytesCount, int count,
- const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode,
+ const float* positions, FontRenderer& fontRenderer, int alpha,
float x, float y);
/**
@@ -849,11 +811,9 @@
void setupDrawAlpha8Color(int color, int alpha);
void setupDrawTextGamma(const SkPaint* paint);
void setupDrawShader();
- void setupDrawColorFilter();
- void setupDrawBlending(SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode,
- bool swapSrcDst = false);
- void setupDrawBlending(bool blend = true, SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode,
- bool swapSrcDst = false);
+ void setupDrawColorFilter(const SkColorFilter* filter);
+ void setupDrawBlending(const Layer* layer, bool swapSrcDst = false);
+ void setupDrawBlending(const SkPaint* paint, bool blend = true, bool swapSrcDst = false);
void setupDrawProgram();
void setupDrawDirtyRegionsDisabled();
@@ -877,7 +837,7 @@
void setupDrawColorUniforms();
void setupDrawPureColorUniforms();
void setupDrawShaderUniforms(bool ignoreTransform = false);
- void setupDrawColorFilterUniforms();
+ void setupDrawColorFilterUniforms(const SkColorFilter* paint);
void setupDrawSimpleMesh();
void setupDrawTexture(GLuint texture);
void setupDrawExternalTexture(GLuint texture);
@@ -906,8 +866,7 @@
* Renders the specified region as a series of rectangles. The region
* must be in screen-space coordinates.
*/
- void drawRegionRects(const SkRegion& region, int color, SkXfermode::Mode mode,
- bool dirty = false);
+ void drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty = false);
/**
* Draws the current clip region if any. Only when DEBUG_CLIP_REGIONS
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 5dfb2fa..33c91b3 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -51,9 +51,8 @@
#define PROGRAM_KEY_GRADIENT 0x8
#define PROGRAM_KEY_BITMAP_FIRST 0x10
#define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_LIGHTING 0x40
-#define PROGRAM_KEY_COLOR_BLEND 0x80
-#define PROGRAM_KEY_BITMAP_NPOT 0x100
+#define PROGRAM_KEY_COLOR_BLEND 0x40
+#define PROGRAM_KEY_BITMAP_NPOT 0x80
#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
@@ -104,7 +103,6 @@
enum ColorModifier {
kColorNone = 0,
kColorMatrix,
- kColorLighting,
kColorBlend
};
@@ -248,9 +246,6 @@
case kColorMatrix:
key |= PROGRAM_KEY_COLOR_MATRIX;
break;
- case kColorLighting:
- key |= PROGRAM_KEY_COLOR_LIGHTING;
- break;
case kColorBlend:
key |= PROGRAM_KEY_COLOR_BLEND;
key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index a5ce6f6..6d50410 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -148,15 +148,12 @@
};
const char* gFS_Uniforms_BitmapSampler =
"uniform sampler2D bitmapSampler;\n";
-const char* gFS_Uniforms_ColorOp[4] = {
+const char* gFS_Uniforms_ColorOp[3] = {
// None
"",
// Matrix
"uniform mat4 colorMatrix;\n"
"uniform vec4 colorMatrixVector;\n",
- // Lighting
- "uniform vec4 lightingMul;\n"
- "uniform vec4 lightingAdd;\n",
// PorterDuff
"uniform vec4 colorBlend;\n"
};
@@ -311,17 +308,13 @@
" gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
const char* gFS_Main_FragColor_Blend_Swap =
" gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n";
-const char* gFS_Main_ApplyColorOp[4] = {
+const char* gFS_Main_ApplyColorOp[3] = {
// None
"",
// Matrix
" fragColor *= colorMatrix;\n"
" fragColor += colorMatrixVector;\n"
" fragColor.rgb *= fragColor.a;\n",
- // Lighting
- " float lightingAlpha = fragColor.a;\n"
- " fragColor = min(fragColor * lightingMul + (lightingAdd * lightingAlpha), lightingAlpha);\n"
- " fragColor.a = lightingAlpha;\n",
// PorterDuff
" fragColor = blendColors(colorBlend, fragColor);\n"
};
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 4799b32..4754bad 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -146,22 +146,15 @@
virtual void restore() = 0;
virtual void restoreToCount(int saveCount) = 0;
- int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
- SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
- int alpha = 255;
- if (paint) {
- mode = getXfermode(paint->getXfermode());
- alpha = paint->getAlpha();
- }
- return saveLayer(left, top, right, bottom, alpha, mode, flags);
- }
+ virtual int saveLayer(float left, float top, float right, float bottom,
+ const SkPaint* paint, int flags) = 0;
+
int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags) {
- return saveLayer(left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
+ SkPaint paint;
+ paint.setAlpha(alpha);
+ return saveLayer(left, top, right, bottom, &paint, flags);
}
- virtual int saveLayer(float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode, int flags) = 0;
// Matrix
virtual void getMatrix(SkMatrix* outMatrix) const = 0;
@@ -185,9 +178,6 @@
virtual void resetShader() = 0;
virtual void setupShader(SkiaShader* shader) = 0;
- virtual void resetColorFilter() = 0;
- virtual void setupColorFilter(SkiaColorFilter* filter) = 0;
-
virtual void resetShadow() = 0;
virtual void setupShadow(float radius, float dx, float dy, int color) = 0;
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index e58857c..457cfa9 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -76,11 +76,6 @@
incrementRefcount((void*) shaderResource, kShader);
}
-void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
- SkSafeRef(filterResource->getSkColorFilter());
- incrementRefcount((void*) filterResource, kColorFilter);
-}
-
void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
incrementRefcount((void*) patchResource, kNinePatch);
}
@@ -114,11 +109,6 @@
incrementRefcountLocked((void*) shaderResource, kShader);
}
-void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) {
- SkSafeRef(filterResource->getSkColorFilter());
- incrementRefcountLocked((void*) filterResource, kColorFilter);
-}
-
void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
incrementRefcountLocked((void*) patchResource, kNinePatch);
}
@@ -147,11 +137,6 @@
decrementRefcount((void*) shaderResource);
}
-void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
- SkSafeUnref(filterResource->getSkColorFilter());
- decrementRefcount((void*) filterResource);
-}
-
void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
decrementRefcount((void*) patchResource);
}
@@ -188,11 +173,6 @@
decrementRefcountLocked((void*) shaderResource);
}
-void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) {
- SkSafeUnref(filterResource->getSkColorFilter());
- decrementRefcountLocked((void*) filterResource);
-}
-
void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
decrementRefcountLocked((void*) patchResource);
}
@@ -264,25 +244,6 @@
}
}
-void ResourceCache::destructor(SkiaColorFilter* resource) {
- Mutex::Autolock _l(mLock);
- destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(SkiaColorFilter* resource) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL) {
- // If we're not tracking this resource, just delete it
- delete resource;
- return;
- }
- ref->destroyed = true;
- if (ref->refCount == 0) {
- deleteResourceReferenceLocked(resource, ref);
- }
-}
-
void ResourceCache::destructor(Res_png_9patch* resource) {
Mutex::Autolock _l(mLock);
destructorLocked(resource);
@@ -372,11 +333,6 @@
delete shader;
}
break;
- case kColorFilter: {
- SkiaColorFilter* filter = (SkiaColorFilter*) resource;
- delete filter;
- }
- break;
case kNinePatch: {
if (Caches::hasInstance()) {
Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index c06b09b..4097ba4 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -20,7 +20,6 @@
#include <cutils/compiler.h>
#include <SkBitmap.h>
-#include <SkiaColorFilter.h>
#include <SkiaShader.h>
#include <utils/KeyedVector.h>
@@ -38,7 +37,6 @@
enum ResourceType {
kBitmap,
kShader,
- kColorFilter,
kNinePatch,
kPath,
kLayer
@@ -73,41 +71,35 @@
void incrementRefcount(const SkPath* resource);
void incrementRefcount(const SkBitmap* resource);
void incrementRefcount(SkiaShader* resource);
- void incrementRefcount(SkiaColorFilter* resource);
void incrementRefcount(const Res_png_9patch* resource);
void incrementRefcount(Layer* resource);
void incrementRefcountLocked(const SkPath* resource);
void incrementRefcountLocked(const SkBitmap* resource);
void incrementRefcountLocked(SkiaShader* resource);
- void incrementRefcountLocked(SkiaColorFilter* resource);
void incrementRefcountLocked(const Res_png_9patch* resource);
void incrementRefcountLocked(Layer* resource);
void decrementRefcount(const SkBitmap* resource);
void decrementRefcount(const SkPath* resource);
void decrementRefcount(SkiaShader* resource);
- void decrementRefcount(SkiaColorFilter* resource);
void decrementRefcount(const Res_png_9patch* resource);
void decrementRefcount(Layer* resource);
void decrementRefcountLocked(const SkBitmap* resource);
void decrementRefcountLocked(const SkPath* resource);
void decrementRefcountLocked(SkiaShader* resource);
- void decrementRefcountLocked(SkiaColorFilter* resource);
void decrementRefcountLocked(const Res_png_9patch* resource);
void decrementRefcountLocked(Layer* resource);
void destructor(SkPath* resource);
void destructor(const SkBitmap* resource);
void destructor(SkiaShader* resource);
- void destructor(SkiaColorFilter* resource);
void destructor(Res_png_9patch* resource);
void destructorLocked(SkPath* resource);
void destructorLocked(const SkBitmap* resource);
void destructorLocked(SkiaShader* resource);
- void destructorLocked(SkiaColorFilter* resource);
void destructorLocked(Res_png_9patch* resource);
bool recycle(SkBitmap* resource);
diff --git a/libs/hwui/SkiaColorFilter.cpp b/libs/hwui/SkiaColorFilter.cpp
deleted file mode 100644
index df918be..0000000
--- a/libs/hwui/SkiaColorFilter.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.
- */
-
-#include "SkiaColorFilter.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Base color filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaColorFilter::SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend):
- mType(type), mBlend(blend), mSkFilter(skFilter) {
-}
-
-SkiaColorFilter::~SkiaColorFilter() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Color matrix filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaColorMatrixFilter::SkiaColorMatrixFilter(SkColorFilter* skFilter, float* matrix, float* vector):
- SkiaColorFilter(skFilter, kColorMatrix, true), mMatrix(matrix), mVector(vector) {
- // Skia uses the range [0..255] for the addition vector, but we need
- // the [0..1] range to apply the vector in GLSL
- for (int i = 0; i < 4; i++) {
- mVector[i] /= 255.0f;
- }
-
- // TODO: We should be smarter about this
- mBlend = true;
-}
-
-SkiaColorMatrixFilter::~SkiaColorMatrixFilter() {
- delete[] mMatrix;
- delete[] mVector;
-}
-
-void SkiaColorMatrixFilter::describe(ProgramDescription& description,
- const Extensions& extensions) {
- description.colorOp = ProgramDescription::kColorMatrix;
-}
-
-void SkiaColorMatrixFilter::setupProgram(Program* program) {
- glUniformMatrix4fv(program->getUniform("colorMatrix"), 1, GL_FALSE, &mMatrix[0]);
- glUniform4fv(program->getUniform("colorMatrixVector"), 1, mVector);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Lighting color filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaLightingFilter::SkiaLightingFilter(SkColorFilter* skFilter, int multiply, int add):
- SkiaColorFilter(skFilter, kLighting, true) {
- mMulR = ((multiply >> 16) & 0xFF) / 255.0f;
- mMulG = ((multiply >> 8) & 0xFF) / 255.0f;
- mMulB = ((multiply ) & 0xFF) / 255.0f;
-
- mAddR = ((add >> 16) & 0xFF) / 255.0f;
- mAddG = ((add >> 8) & 0xFF) / 255.0f;
- mAddB = ((add ) & 0xFF) / 255.0f;
-
- // A lighting filter always ignores alpha
- mBlend = false;
-}
-
-void SkiaLightingFilter::describe(ProgramDescription& description, const Extensions& extensions) {
- description.colorOp = ProgramDescription::kColorLighting;
-}
-
-void SkiaLightingFilter::setupProgram(Program* program) {
- glUniform4f(program->getUniform("lightingMul"), mMulR, mMulG, mMulB, 1.0f);
- glUniform4f(program->getUniform("lightingAdd"), mAddR, mAddG, mAddB, 0.0f);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Blend color filter
-///////////////////////////////////////////////////////////////////////////////
-
-SkiaBlendFilter::SkiaBlendFilter(SkColorFilter* skFilter, int color, SkXfermode::Mode mode):
- SkiaColorFilter(skFilter, kBlend, true), mMode(mode) {
- const int alpha = (color >> 24) & 0xFF;
- mA = alpha / 255.0f;
- mR = mA * ((color >> 16) & 0xFF) / 255.0f;
- mG = mA * ((color >> 8) & 0xFF) / 255.0f;
- mB = mA * ((color ) & 0xFF) / 255.0f;
-
- // TODO: We should do something smarter here
- mBlend = true;
-}
-
-void SkiaBlendFilter::describe(ProgramDescription& description, const Extensions& extensions) {
- description.colorOp = ProgramDescription::kColorBlend;
- description.colorMode = mMode;
-}
-
-void SkiaBlendFilter::setupProgram(Program* program) {
- glUniform4f(program->getUniform("colorBlend"), mR, mG, mB, mA);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
deleted file mode 100644
index c222a2d..0000000
--- a/libs/hwui/SkiaColorFilter.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HWUI_SKIA_COLOR_FILTER_H
-#define ANDROID_HWUI_SKIA_COLOR_FILTER_H
-
-#include <GLES2/gl2.h>
-#include <SkColorFilter.h>
-
-#include <cutils/compiler.h>
-
-#include "ProgramCache.h"
-#include "Extensions.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Base color filter
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Represents a Skia color filter. A color filter modifies a ProgramDescription
- * and sets uniforms on the resulting shaders.
- */
-class SkiaColorFilter {
-public:
- /**
- * Type of Skia color filter in use.
- */
- enum Type {
- kNone,
- kColorMatrix,
- kLighting,
- kBlend,
- };
-
- ANDROID_API SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
- virtual ~SkiaColorFilter();
-
- virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0;
- virtual void setupProgram(Program* program) = 0;
-
- inline bool blend() const {
- return mBlend;
- }
-
- Type type() const {
- return mType;
- }
-
- SkColorFilter* getSkColorFilter() {
- return mSkFilter;
- }
-
-protected:
- Type mType;
- bool mBlend;
-
-private:
- SkColorFilter *mSkFilter;
-}; // struct SkiaColorFilter
-
-///////////////////////////////////////////////////////////////////////////////
-// Implementations
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * A color filter that multiplies the source color with a matrix and adds a vector.
- */
-class SkiaColorMatrixFilter: public SkiaColorFilter {
-public:
- ANDROID_API SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
- ~SkiaColorMatrixFilter();
-
- void describe(ProgramDescription& description, const Extensions& extensions);
- void setupProgram(Program* program);
-
-private:
- float* mMatrix;
- float* mVector;
-}; // struct SkiaColorMatrixFilter
-
-/**
- * A color filters that multiplies the source color with a fixed value and adds
- * another fixed value. Ignores the alpha channel of both arguments.
- */
-class SkiaLightingFilter: public SkiaColorFilter {
-public:
- ANDROID_API SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
-
- void describe(ProgramDescription& description, const Extensions& extensions);
- void setupProgram(Program* program);
-
-private:
- GLfloat mMulR, mMulG, mMulB;
- GLfloat mAddR, mAddG, mAddB;
-}; // struct SkiaLightingFilter
-
-/**
- * A color filters that blends the source color with a specified destination color
- * and PorterDuff blending mode.
- */
-class SkiaBlendFilter: public SkiaColorFilter {
-public:
- ANDROID_API SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
-
- void describe(ProgramDescription& description, const Extensions& extensions);
- void setupProgram(Program* program);
-
-private:
- SkXfermode::Mode mMode;
- GLfloat mR, mG, mB, mA;
-}; // struct SkiaBlendFilter
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_SKIA_COLOR_FILTER_H
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index a6ec183..d26ee38 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -70,10 +70,6 @@
} else {
region = NULL;
}
-
- if (saveFlags & Snapshot::kFlagProjectionTarget) {
- flags |= Snapshot::kFlagProjectionTarget;
- }
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index d61d972..cc6d0cd 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -75,13 +75,7 @@
* Indicates that this snapshot or an ancestor snapshot is
* an FBO layer.
*/
- kFlagFboTarget = 0x10,
- /**
- * Indicates that the save/restore pair encapsulates a
- * projection target, and that after the restore any projected
- * descendents should be drawn.
- */
- kFlagProjectionTarget = 0x20
+ kFlagFboTarget = 0x10
};
/**
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7c3c197..2806bff 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -22,8 +22,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetFileDescriptor;
-import android.net.Proxy;
-import android.net.ProxyProperties;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
@@ -882,8 +880,6 @@
*/
public void setDataSource(Context context, Uri uri, Map<String, String> headers)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
- disableProxyListener();
-
String scheme = uri.getScheme();
if(scheme == null || scheme.equals("file")) {
setDataSource(uri.getPath());
@@ -917,11 +913,6 @@
Log.d(TAG, "Couldn't open file on client side, trying server side");
setDataSource(uri.toString(), headers);
-
- if (scheme.equalsIgnoreCase("http")
- || scheme.equalsIgnoreCase("https")) {
- setupProxyListener(context);
- }
}
/**
@@ -972,8 +963,6 @@
private void setDataSource(String path, String[] keys, String[] values)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
- disableProxyListener();
-
final Uri uri = Uri.parse(path);
if ("file".equals(uri.getScheme())) {
path = uri.getPath();
@@ -1029,7 +1018,6 @@
*/
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
- disableProxyListener();
_setDataSource(fd, offset, length);
}
@@ -1401,8 +1389,6 @@
if (mEventHandler != null) {
mEventHandler.removeCallbacksAndMessages(null);
}
-
- disableProxyListener();
}
private native void _reset();
@@ -2750,59 +2736,6 @@
mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
}
- private Context mProxyContext = null;
- private ProxyReceiver mProxyReceiver = null;
-
- private void setupProxyListener(Context context) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Proxy.PROXY_CHANGE_ACTION);
- mProxyReceiver = new ProxyReceiver();
- mProxyContext = context;
-
- Intent currentProxy =
- context.getApplicationContext().registerReceiver(mProxyReceiver, filter);
-
- if (currentProxy != null) {
- handleProxyBroadcast(currentProxy);
- }
- }
-
- private void disableProxyListener() {
- if (mProxyReceiver == null) {
- return;
- }
-
- Context appContext = mProxyContext.getApplicationContext();
- if (appContext != null) {
- appContext.unregisterReceiver(mProxyReceiver);
- }
-
- mProxyReceiver = null;
- mProxyContext = null;
- }
-
- private void handleProxyBroadcast(Intent intent) {
- ProxyProperties props =
- (ProxyProperties)intent.getExtra(Proxy.EXTRA_PROXY_INFO);
-
- if (props == null || props.getHost() == null) {
- updateProxyConfig(null);
- } else {
- updateProxyConfig(props);
- }
- }
-
- private class ProxyReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(Proxy.PROXY_CHANGE_ACTION)) {
- handleProxyBroadcast(intent);
- }
- }
- }
-
- private native void updateProxyConfig(ProxyProperties props);
-
/** @hide */
static class TimeProvider implements MediaPlayer.OnSeekCompleteListener,
MediaTimeProvider {
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 2af1c12..dc3ae5b 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -816,52 +816,6 @@
;
}
-static void
-android_media_MediaPlayer_updateProxyConfig(
- JNIEnv *env, jobject thiz, jobject proxyProps)
-{
- ALOGV("updateProxyConfig");
- sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz);
- if (thisplayer == NULL) {
- return;
- }
-
- if (proxyProps == NULL) {
- thisplayer->updateProxyConfig(
- NULL /* host */, 0 /* port */, NULL /* exclusionList */);
- } else {
- jstring hostObj = (jstring)env->CallObjectMethod(
- proxyProps, fields.proxyConfigGetHost);
-
- const char *host = env->GetStringUTFChars(hostObj, NULL);
-
- int port = env->CallIntMethod(proxyProps, fields.proxyConfigGetPort);
-
- jstring exclusionListObj = (jstring)env->CallObjectMethod(
- proxyProps, fields.proxyConfigGetExclusionList);
-
- if (host != NULL && exclusionListObj != NULL) {
- const char *exclusionList = env->GetStringUTFChars(exclusionListObj, NULL);
-
- if (exclusionList != NULL) {
- thisplayer->updateProxyConfig(host, port, exclusionList);
-
- env->ReleaseStringUTFChars(exclusionListObj, exclusionList);
- exclusionList = NULL;
- } else {
- thisplayer->updateProxyConfig(host, port, "");
- }
- } else if (host != NULL) {
- thisplayer->updateProxyConfig(host, port, "");
- }
-
- if (host != NULL) {
- env->ReleaseStringUTFChars(hostObj, host);
- host = NULL;
- }
- }
-}
-
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
@@ -904,7 +858,6 @@
{"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
{"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint},
{"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer},
- {"updateProxyConfig", "(Landroid/net/ProxyProperties;)V", (void *)android_media_MediaPlayer_updateProxyConfig},
};
static const char* const kClassPathName = "android/media/MediaPlayer";
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index f6f441d..1f2b5fb 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -18,8 +18,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
-LOCAL_JAVA_LIBRARIES := services
-
LOCAL_PACKAGE_NAME := Keyguard
LOCAL_CERTIFICATE := platform
diff --git a/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml b/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml
new file mode 100644
index 0000000..cba7667
--- /dev/null
+++ b/packages/Keyguard/res/layout-port/keyguard_simple_host_view.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+ and the security view. -->
+<com.android.keyguard.KeyguardSimpleHostView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+ android:id="@+id/keyguard_host_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.android.keyguard.KeyguardSecurityContainer
+ android:id="@+id/keyguard_security_container"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/keyguard_security_height"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:padding="0dp"
+ android:layout_gravity="center">
+ <com.android.keyguard.KeyguardSecurityViewFlipper
+ android:id="@+id/view_flipper"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/keyguard_security_view_margin"
+ android:gravity="center">
+ </com.android.keyguard.KeyguardSecurityViewFlipper>
+ </com.android.keyguard.KeyguardSecurityContainer>
+
+</com.android.keyguard.KeyguardSimpleHostView>
+
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 1548dee..7ac94bd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -17,15 +17,14 @@
package com.android.keyguard;
import android.nfc.NfcUnlock;
+
import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.KeyguardUpdateMonitor.DisplayClientState;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.AlertDialog;
import android.app.SearchManager;
import android.app.admin.DevicePolicyManager;
import android.appwidget.AppWidgetHost;
@@ -39,9 +38,9 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
-import android.graphics.Canvas;
import android.graphics.Rect;
import android.media.RemoteControlClient;
+import android.os.Bundle;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
@@ -51,12 +50,9 @@
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Slog;
-
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.WindowManager;
import android.widget.RemoteViews.OnClickHandler;
import java.io.File;
@@ -65,6 +61,8 @@
public class KeyguardHostView extends KeyguardViewBase {
private static final String TAG = "KeyguardHostView";
+ public static boolean DEBUG = KeyguardViewMediator.DEBUG;
+ public static boolean DEBUGXPORT = true; // debug music transport control
// Transport control states.
static final int TRANSPORT_GONE = 0;
@@ -73,13 +71,8 @@
private int mTransportState = TRANSPORT_GONE;
- // Use this to debug all of keyguard
- public static boolean DEBUG = KeyguardViewMediator.DEBUG;
- public static boolean DEBUGXPORT = true; // debug music transport control
-
// Found in KeyguardAppWidgetPickActivity.java
static final int APPWIDGET_HOST_ID = 0x4B455947;
-
private final int MAX_WIDGETS = 5;
private AppWidgetHost mAppWidgetHost;
@@ -89,18 +82,13 @@
private int mAppWidgetToShow;
protected int mFailedAttempts;
- private LockPatternUtils mLockPatternUtils;
private KeyguardViewStateManager mViewStateManager;
private Rect mTempRect = new Rect();
-
private int mDisabledFeatures;
-
private boolean mCameraDisabled;
-
private boolean mSafeModeEnabled;
-
private boolean mUserSetupCompleted;
// User for whom this host view was created. Final because we should never change the
@@ -119,8 +107,6 @@
private Runnable mPostBootCompletedRunnable;
- private OnDismissAction mDismissAction;
-
/*package*/ interface UserSwitcherCallback {
void hideSecurityView(int duration);
void showSecurityView();
@@ -309,27 +295,18 @@
private SlidingChallengeLayout mSlidingChallengeLayout;
private MultiPaneChallengeLayout mMultiPaneChallengeLayout;
- private KeyguardSecurityContainer mSecurityContainer;
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean result = super.onTouchEvent(ev);
mTempRect.set(0, 0, 0, 0);
- offsetRectIntoDescendantCoords(mSecurityContainer, mTempRect);
+ offsetRectIntoDescendantCoords(getSecurityContainer(), mTempRect);
ev.offsetLocation(mTempRect.left, mTempRect.top);
- result = mSecurityContainer.dispatchTouchEvent(ev) || result;
+ result = getSecurityContainer().dispatchTouchEvent(ev) || result;
ev.offsetLocation(-mTempRect.left, -mTempRect.top);
return result;
}
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.keyguardDoneDrawing();
- }
- }
-
private int getWidgetPosition(int id) {
final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer;
final int children = appWidgetContainer.getChildCount();
@@ -347,6 +324,8 @@
@Override
protected void onFinishInflate() {
+ super.onFinishInflate();
+
// Grab instances of and make any necessary changes to the main layouts. Create
// view state manager and wire up necessary listeners / callbacks.
View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
@@ -372,49 +351,7 @@
mViewStateManager.setPagedView(mAppWidgetContainer);
mViewStateManager.setChallengeLayout(challenge);
- mSecurityContainer =
- (KeyguardSecurityContainer) findViewById(R.id.keyguard_security_container);
- mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
- mSecurityContainer.setSecurityCallback(new SecurityCallback() {
- @Override
- public void userActivity(long timeout) {
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.userActivity(timeout);
- }
- }
-
- @Override
- public void dismiss(boolean authenticated) {
- KeyguardHostView.this.dismiss(authenticated);
- }
-
- @Override
- public void finish() {
-
- // If the alternate unlock was suppressed, it can now be safely
- // enabled because the user has left keyguard.
- KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
-
- // If there's a pending runnable because the user interacted with a widget
- // and we're leaving keyguard, then run it.
- boolean deferKeyguardDone = false;
- if (mDismissAction != null) {
- deferKeyguardDone = mDismissAction.onDismiss();
- mDismissAction = null;
- }
- if (mViewMediatorCallback != null) {
- if (deferKeyguardDone) {
- mViewMediatorCallback.keyguardDonePending();
- } else {
- mViewMediatorCallback.keyguardDone(true);
- }
- }
- }
- });
-
- mViewStateManager.setSecurityViewContainer(mSecurityContainer);
-
- setBackButtonEnabled(false);
+ mViewStateManager.setSecurityViewContainer(getSecurityContainer());
if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
updateAndAddWidgets();
@@ -429,8 +366,7 @@
};
}
- mSecurityContainer.showPrimarySecurityScreen(false);
- mSecurityContainer.updateSecurityViews(mViewStateManager.isBouncing());
+ getSecurityContainer().updateSecurityViews(mViewStateManager.isBouncing());
enableUserSelectorIfNecessary();
}
@@ -459,17 +395,37 @@
}
}
- private void setBackButtonEnabled(boolean enabled) {
- if (mContext instanceof Activity) return; // always enabled in activity mode
- setSystemUiVisibility(enabled ?
- getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
- getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
- }
-
private boolean shouldEnableAddWidget() {
return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
}
+ @Override
+ public boolean dismiss(boolean authenticated) {
+ boolean finished = super.dismiss(authenticated);
+ if (!finished) {
+ mViewStateManager.showBouncer(true);
+
+ // Enter full screen mode if we're in SIM or Account screen
+ SecurityMode securityMode = getSecurityContainer().getSecurityMode();
+ boolean isFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
+ boolean isSimOrAccount = securityMode == SecurityMode.SimPin
+ || securityMode == SecurityMode.SimPuk
+ || securityMode == SecurityMode.Account;
+ mAppWidgetContainer.setVisibility(
+ isSimOrAccount && isFullScreen ? View.GONE : View.VISIBLE);
+
+ // Don't show camera or search in navbar when SIM or Account screen is showing
+ setSystemUiVisibility(isSimOrAccount ?
+ (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH)
+ : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH));
+
+ if (mSlidingChallengeLayout != null) {
+ mSlidingChallengeLayout.setChallengeInteractive(!isFullScreen);
+ }
+ }
+ return finished;
+ }
+
private int getDisabledFeatures(DevicePolicyManager dpm) {
int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
if (dpm != null) {
@@ -492,10 +448,10 @@
|| (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
}
- void setLockPatternUtils(LockPatternUtils utils) {
- mLockPatternUtils = utils;
- mSecurityContainer.setLockPatternUtils(utils);
- mSecurityContainer.updateSecurityViews(mViewStateManager.isBouncing());
+ @Override
+ protected void setLockPatternUtils(LockPatternUtils utils) {
+ super.setLockPatternUtils(utils);
+ getSecurityContainer().updateSecurityViews(mViewStateManager.isBouncing());
}
@Override
@@ -554,7 +510,8 @@
}
};
- public void initializeSwitchingUserState(boolean switching) {
+ @Override
+ public void onUserSwitching(boolean switching) {
if (!switching && mKeyguardMultiUserSelectorView != null) {
mKeyguardMultiUserSelectorView.finalizeActiveUserView(false);
}
@@ -582,8 +539,6 @@
return -1;
}
-
-
private static class MyOnClickHandler extends OnClickHandler {
// weak reference to the hostView to avoid keeping a live reference
@@ -641,75 +596,31 @@
@Override
public void onScreenTurnedOn() {
- if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
- mSecurityContainer.showPrimarySecurityScreen(false);
- mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
-
- // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
- // layout is blank but forcing a layout causes it to reappear (e.g. with with
- // hierarchyviewer).
- requestLayout();
-
+ super.onScreenTurnedOn();
if (mViewStateManager != null) {
mViewStateManager.showUsabilityHints();
}
-
- requestFocus();
}
@Override
public void onScreenTurnedOff() {
- if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
- Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
- // Once the screen turns off, we no longer consider this to be first boot and we want the
- // biometric unlock to start next time keyguard is shown.
- KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+ super.onScreenTurnedOff();
// We use mAppWidgetToShow to show a particular widget after you add it-- once the screen
// turns off we reset that behavior
clearAppWidgetToShow();
if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
checkAppWidgetConsistency();
}
- mSecurityContainer.showPrimarySecurityScreen(true);
- mSecurityContainer.onPause();
CameraWidgetFrame cameraPage = findCameraPage();
if (cameraPage != null) {
cameraPage.onScreenTurnedOff();
}
-
- clearFocus();
}
public void clearAppWidgetToShow() {
mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
}
- @Override
- public void show() {
- if (DEBUG) Log.d(TAG, "show()");
- mSecurityContainer.showPrimarySecurityScreen(false);
- }
-
- @Override
- public void verifyUnlock() {
- SecurityMode securityMode = mSecurityContainer.getSecurityMode();
- if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.keyguardDone(true);
- }
- } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
- && securityMode != KeyguardSecurityModel.SecurityMode.PIN
- && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
- // can only verify unlock when in pattern/password mode
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.keyguardDone(false);
- }
- } else {
- // otherwise, go to the unlock screen, see if they can verify it
- mSecurityContainer.verifyUnlock();
- }
- }
-
private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
if (appWidgetInfo != null) {
@@ -757,28 +668,6 @@
}
};
- private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
- @Override
- Context getContext() {
- return mContext;
- }
-
- @Override
- void setOnDismissAction(OnDismissAction action) {
- mDismissAction = action;
- }
-
- @Override
- LockPatternUtils getLockPatternUtils() {
- return mLockPatternUtils;
- }
-
- @Override
- void requestDismissKeyguard() {
- KeyguardHostView.this.dismiss(false);
- }
- };
-
private int numWidgets() {
final int childCount = mAppWidgetContainer.getChildCount();
int widgetCount = 0;
@@ -800,7 +689,7 @@
@Override
public void onClick(View v) {
// Pass in an invalid widget id... the picker will allocate an ID for us
- mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
+ getActivityLauncher().launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
}
});
}
@@ -810,8 +699,8 @@
// inflate system-provided camera?
if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted
&& mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
- View cameraWidget =
- CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher);
+ View cameraWidget = CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks,
+ getActivityLauncher());
if (cameraWidget != null) {
mAppWidgetContainer.addWidget(cameraWidget);
}
@@ -1198,18 +1087,18 @@
UserSwitcherCallback callback = new UserSwitcherCallback() {
@Override
public void hideSecurityView(int duration) {
- mSecurityContainer.animate().alpha(0).setDuration(duration);
+ getSecurityContainer().animate().alpha(0).setDuration(duration);
}
@Override
public void showSecurityView() {
- mSecurityContainer.setAlpha(1.0f);
+ getSecurityContainer().setAlpha(1.0f);
}
@Override
public void showUnlockHint() {
- if (mSecurityContainer != null) {
- mSecurityContainer.showUsabilityHint();
+ if (getSecurityContainer() != null) {
+ getSecurityContainer().showUsabilityHint();
}
}
@@ -1244,124 +1133,31 @@
}
}
- /**
- * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
- * some cases where we wish to disable it, notably when the menu button placement or technology
- * is prone to false positives.
- *
- * @return true if the menu key should be enabled
- */
- private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
- private boolean shouldEnableMenuKey() {
- final Resources res = getResources();
- final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
- final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
- final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
- return !configDisabled || isTestHarness || fileOverride;
- }
-
public void goToWidget(int appWidgetId) {
mAppWidgetToShow = appWidgetId;
mSwitchPageRunnable.run();
}
- public boolean handleMenuKey() {
- // The following enables the MENU key to work for testing automation
- if (shouldEnableMenuKey()) {
- dismiss();
- return true;
- }
- return false;
+ @Override
+ protected void showBouncer(boolean show) {
+ super.showBouncer(show);
+ mViewStateManager.showBouncer(show);
}
- public boolean handleBackKey() {
- if (mSecurityContainer.getCurrentSecuritySelection() == SecurityMode.Account) {
- // go back to primary screen and re-disable back
- setBackButtonEnabled(false);
- mSecurityContainer.showPrimarySecurityScreen(false /*turningOff*/);
- return true;
- }
- if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
- mSecurityContainer.dismiss(false);
- return true;
- }
- return false;
- }
-
- /**
- * Dismisses the keyguard by going to the next screen or making it gone.
- */
- public void dismiss() {
- dismiss(false);
- }
-
- private void dismiss(boolean authenticated) {
- boolean finished = mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
- if (!finished) {
- updateAfterSecuritySelection();
- mViewStateManager.showBouncer(true);
- }
- }
-
- void setOnDismissAction(OnDismissAction action) {
- mDismissAction = action;
- }
-
- public void announceCurrentSecurityMethod() {
- mSecurityContainer.announceCurrentSecurityMethod();
- }
-
- private void updateAfterSecuritySelection() {
- // Enable or disable the back button based on security mode
- if (mSecurityContainer.getSecurityMode() == SecurityMode.Account
- && !mLockPatternUtils.isPermanentlyLocked()) {
- // we're showing account as a backup, provide a way to get back to primary
- setBackButtonEnabled(true);
- }
-
- // Enter full screen mode if we're in SIM or Account screen
- SecurityMode securityMode = mSecurityContainer.getSecurityMode();
- boolean isFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
- boolean isSimOrAccount = securityMode == SecurityMode.SimPin
- || securityMode == SecurityMode.SimPuk
- || securityMode == SecurityMode.Account;
- mAppWidgetContainer.setVisibility(
- isSimOrAccount && isFullScreen ? View.GONE : View.VISIBLE);
-
- // Don't show camera or search in navbar when SIM or Account screen is showing
- setSystemUiVisibility(isSimOrAccount ?
- (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH)
- : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH));
-
- if (mSlidingChallengeLayout != null) {
- mSlidingChallengeLayout.setChallengeInteractive(!isFullScreen);
- }
-
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
- }
- }
-
- public void showAssistant() {
- final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
- .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
-
- if (intent == null) return;
-
- final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
- R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
- getHandler(), null);
-
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mActivityLauncher.launchActivityWithAnimation(intent, false, opts.toBundle(), null, null);
- }
-
- public void dispatch(MotionEvent event) {
+ @Override
+ public void onExternalMotionEvent(MotionEvent event) {
mAppWidgetContainer.handleExternalCameraEvent(event);
}
- public void launchCamera() {
- mActivityLauncher.launchCamera(getHandler(), null);
+ @Override
+ protected void onCreateOptions(Bundle options) {
+ if (options != null) {
+ int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
+ goToWidget(widgetToShow);
+ }
+ }
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index ea92b649..0f62100 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -44,8 +44,9 @@
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
- public void dismiss(boolean authenticated);
+ public boolean dismiss(boolean authenticated);
public void userActivity(long timeout);
+ public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
public void finish();
}
@@ -293,18 +294,12 @@
showSecurityScreen(backup);
}
- private boolean showNextSecurityScreenIfPresent() {
- SecurityMode securityMode = mSecurityModel.getSecurityMode();
- // Allow an alternate, such as biometric unlock
- securityMode = mSecurityModel.getAlternateFor(securityMode);
- if (SecurityMode.None == securityMode) {
- return false;
- } else {
- showSecurityScreen(securityMode); // switch to the alternate security view
- return true;
- }
- }
-
+ /**
+ * Shows the next security screen if there is one.
+ * @param authenticated true if the user entered the correct authentication
+ * @param authenticated
+ * @return true if keyguard is done
+ */
boolean showNextSecurityScreenOrFinish(boolean authenticated) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
boolean finish = false;
@@ -386,6 +381,7 @@
}
mCurrentSecuritySelection = securityMode;
+ mSecurityCallback.onSecurityModeChanged(securityMode, newView.needsInput());
}
private KeyguardSecurityViewFlipper getFlipper() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 4129e33..9f5768a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -105,7 +105,7 @@
break;
default:
- throw new IllegalStateException("Unknown unlock mode:" + mode);
+ throw new IllegalStateException("Unknown security quality:" + security);
}
}
return mode;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
new file mode 100644
index 0000000..cf983cb
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
@@ -0,0 +1,70 @@
+/*
+ * 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.keyguard;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class KeyguardSimpleHostView extends KeyguardViewBase {
+
+ public KeyguardSimpleHostView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void showBouncer(boolean show) {
+ super.showBouncer(show);
+ if (show) {
+ getSecurityContainer().showBouncer(250);
+ } else {
+ getSecurityContainer().hideBouncer(250);
+ }
+ }
+
+ @Override
+ public void verifyUnlock() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void cleanUp() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public long getUserActivityTimeout() {
+ return -1; // not used
+ }
+
+ @Override
+ protected void onUserSwitching(boolean switching) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ protected void onCreateOptions(Bundle options) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ protected void onExternalMotionEvent(MotionEvent event) {
+ // TODO Auto-generated method stub
+ }
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index bff1f93..78f4506 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -17,18 +17,36 @@
package com.android.keyguard;
import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.SearchManager;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Canvas;
import android.media.AudioManager;
import android.media.IAudioService;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
import android.widget.FrameLayout;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+
+import java.io.File;
+
/**
* Base class for keyguard view. {@link #reset} is where you should
* reset the state of your view. Use the {@link KeyguardViewCallback} via
@@ -38,16 +56,22 @@
* Handles intercepting of media keys that still work when the keyguard is
* showing.
*/
-public abstract class KeyguardViewBase extends FrameLayout {
+public abstract class KeyguardViewBase extends FrameLayout implements SecurityCallback {
private AudioManager mAudioManager;
private TelephonyManager mTelephonyManager = null;
protected KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
+ protected LockPatternUtils mLockPatternUtils;
+ private OnDismissAction mDismissAction;
// Whether the volume keys should be handled by keyguard. If true, then
// they will be handled here for specific media types such as music, otherwise
// the audio service will bring up the volume dialog.
private static final boolean KEYGUARD_MANAGES_VOLUME = true;
+ private static final boolean DEBUG = false;
+ private static final String TAG = "KeyguardViewBase";
+
+ private KeyguardSecurityContainer mSecurityContainer;
public KeyguardViewBase(Context context) {
this(context, null);
@@ -57,20 +81,181 @@
super(context, attrs);
}
- /**
- * Called when the screen turned off.
- */
- abstract public void onScreenTurnedOff();
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.keyguardDoneDrawing();
+ }
+ }
/**
- * Called when the screen turned on.
+ * Sets an action to run when keyguard finishes.
+ *
+ * @param action
*/
- abstract public void onScreenTurnedOn();
+ public void setOnDismissAction(OnDismissAction action) {
+ mDismissAction = action;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mSecurityContainer =
+ (KeyguardSecurityContainer) findViewById(R.id.keyguard_security_container);
+ mLockPatternUtils = new LockPatternUtils(mContext);
+ mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
+ mSecurityContainer.setSecurityCallback(this);
+ mSecurityContainer.showPrimarySecurityScreen(false);
+ // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
+ setBackButtonEnabled(false);
+ }
/**
* Called when the view needs to be shown.
*/
- abstract public void show();
+ public void show() {
+ if (DEBUG) Log.d(TAG, "show()");
+ mSecurityContainer.showPrimarySecurityScreen(false);
+ }
+
+ /**
+ * Dismisses the keyguard by going to the next screen or making it gone.
+ */
+ public void dismiss() {
+ dismiss(false);
+ }
+
+ private void setBackButtonEnabled(boolean enabled) {
+ setSystemUiVisibility(enabled ?
+ getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
+ getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
+ }
+
+ protected void showBouncer(boolean show) {
+ CharSequence what = getContext().getResources().getText(
+ show ? R.string.keyguard_accessibility_show_bouncer
+ : R.string.keyguard_accessibility_hide_bouncer);
+ announceForAccessibility(what);
+ announceCurrentSecurityMethod();
+ }
+
+ public boolean handleBackKey() {
+ if (mSecurityContainer.getCurrentSecuritySelection() == SecurityMode.Account) {
+ // go back to primary screen and re-disable back
+ setBackButtonEnabled(false);
+ mSecurityContainer.showPrimarySecurityScreen(false /*turningOff*/);
+ return true;
+ }
+ if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
+ mSecurityContainer.dismiss(false);
+ return true;
+ }
+ return false;
+ }
+
+ protected void announceCurrentSecurityMethod() {
+ mSecurityContainer.announceCurrentSecurityMethod();
+ }
+
+ protected KeyguardSecurityContainer getSecurityContainer() {
+ return mSecurityContainer;
+ }
+
+ /**
+ * Extend display timeout
+ * @param timeout duration to delay timeout, in ms.
+ */
+ @Override
+ public void userActivity(long timeout) {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.userActivity(timeout);
+ }
+ }
+
+ @Override
+ public boolean dismiss(boolean authenticated) {
+ return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
+ }
+
+ /**
+ * Authentication has happened and it's time to dismiss keyguard. This function
+ * should clean up and inform KeyguardViewMediator.
+ */
+ @Override
+ public void finish() {
+ // If the alternate unlock was suppressed, it can now be safely
+ // enabled because the user has left keyguard.
+ KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+
+ // If there's a pending runnable because the user interacted with a widget
+ // and we're leaving keyguard, then run it.
+ boolean deferKeyguardDone = false;
+ if (mDismissAction != null) {
+ deferKeyguardDone = mDismissAction.onDismiss();
+ mDismissAction = null;
+ }
+ if (mViewMediatorCallback != null) {
+ if (deferKeyguardDone) {
+ mViewMediatorCallback.keyguardDonePending();
+ } else {
+ mViewMediatorCallback.keyguardDone(true);
+ }
+ }
+ }
+
+ @Override
+ public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
+ // Enable or disable the back button based on security mode
+ if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) {
+ // we're showing account as a backup, provide a way to get back to primary
+ setBackButtonEnabled(true);
+ }
+
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.setNeedsInput(needsInput);
+ }
+ }
+
+ public void userActivity() {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.userActivity();
+ }
+ }
+
+ protected void onUserActivityTimeoutChanged() {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.onUserActivityTimeoutChanged();
+ }
+ }
+
+ /**
+ * Called when the screen turned off.
+ */
+ protected void onScreenTurnedOff() {
+ if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
+ Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
+ // Once the screen turns off, we no longer consider this to be first boot and we want the
+ // biometric unlock to start next time keyguard is shown.
+ KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
+ mSecurityContainer.showPrimarySecurityScreen(true);
+ mSecurityContainer.onPause();
+ clearFocus();
+ }
+
+ /**
+ * Called when the screen turned on.
+ */
+ protected void onScreenTurnedOn() {
+ if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
+ mSecurityContainer.showPrimarySecurityScreen(false);
+ mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
+
+ // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
+ // layout is blank but forcing a layout causes it to reappear (e.g. with with
+ // hierarchyviewer).
+ requestLayout();
+ requestFocus();
+ }
/**
* Verify that the user can get past the keyguard securely. This is called,
@@ -79,7 +264,24 @@
*
* The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
*/
- abstract public void verifyUnlock();
+ public void verifyUnlock() {
+ SecurityMode securityMode = mSecurityContainer.getSecurityMode();
+ if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.keyguardDone(true);
+ }
+ } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
+ && securityMode != KeyguardSecurityModel.SecurityMode.PIN
+ && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
+ // can only verify unlock when in pattern/password mode
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.keyguardDone(false);
+ }
+ } else {
+ // otherwise, go to the unlock screen, see if they can verify it
+ mSecurityContainer.verifyUnlock();
+ }
+ }
/**
* Called before this view is being removed.
@@ -183,7 +385,7 @@
return false;
}
- void handleMediaKeyEvent(KeyEvent keyEvent) {
+ private void handleMediaKeyEvent(KeyEvent keyEvent) {
IAudioService audioService = IAudioService.Stub.asInterface(
ServiceManager.checkService(Context.AUDIO_SERVICE));
if (audioService != null) {
@@ -206,8 +408,91 @@
}
}
+ /**
+ * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
+ * some cases where we wish to disable it, notably when the menu button placement or technology
+ * is prone to false positives.
+ *
+ * @return true if the menu key should be enabled
+ */
+ private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
+ private boolean shouldEnableMenuKey() {
+ final Resources res = getResources();
+ final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+ final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
+ final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+ return !configDisabled || isTestHarness || fileOverride;
+ }
+
+ public boolean handleMenuKey() {
+ // The following enables the MENU key to work for testing automation
+ if (shouldEnableMenuKey()) {
+ dismiss();
+ return true;
+ }
+ return false;
+ }
+
public void setViewMediatorCallback(
KeyguardViewMediator.ViewMediatorCallback viewMediatorCallback) {
mViewMediatorCallback = viewMediatorCallback;
+ // Update ViewMediator with the current input method requirements
+ mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
}
+
+ protected KeyguardActivityLauncher getActivityLauncher() {
+ return mActivityLauncher;
+ }
+
+ private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
+ @Override
+ Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ void setOnDismissAction(OnDismissAction action) {
+ KeyguardViewBase.this.setOnDismissAction(action);
+ }
+
+ @Override
+ LockPatternUtils getLockPatternUtils() {
+ return mLockPatternUtils;
+ }
+
+ @Override
+ void requestDismissKeyguard() {
+ KeyguardViewBase.this.dismiss(false);
+ }
+ };
+
+ public void showAssistant() {
+ final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+ .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
+
+ if (intent == null) return;
+
+ final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
+ getHandler(), null);
+
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mActivityLauncher.launchActivityWithAnimation(intent, false, opts.toBundle(), null, null);
+ }
+
+ public void launchCamera() {
+ mActivityLauncher.launchCamera(getHandler(), null);
+ }
+
+ protected void setLockPatternUtils(LockPatternUtils utils) {
+ mLockPatternUtils = utils;
+ mSecurityContainer.setLockPatternUtils(utils);
+ }
+
+ protected abstract void onUserSwitching(boolean switching);
+
+ protected abstract void onCreateOptions(Bundle options);
+
+ protected abstract void onExternalMotionEvent(MotionEvent event);
+
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index f2853c8..baf520e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -18,11 +18,15 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
+
import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.widget.LockPatternUtils;
+import org.xmlpull.v1.XmlPullParser;
+
import android.app.ActivityManager;
import android.appwidget.AppWidgetManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -38,6 +42,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -75,7 +80,7 @@
private boolean mNeedsInput = false;
private ViewManagerHost mKeyguardHost;
- private KeyguardHostView mKeyguardView;
+ private KeyguardViewBase mKeyguardView;
private boolean mScreenOn = false;
private LockPatternUtils mLockPatternUtils;
@@ -259,6 +264,7 @@
}
SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
+ private int mCurrentLayout;
private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,
Bundle options) {
@@ -306,7 +312,14 @@
if (force || mKeyguardView == null) {
mKeyguardHost.setCustomBackground(null);
mKeyguardHost.removeAllViews();
- inflateKeyguardView(options);
+ int layout = allowNotificationsOnSecureKeyguard()
+ ? R.layout.keyguard_simple_host_view
+ : R.layout.keyguard_host_view;
+ if (mCurrentLayout != layout) {
+ mStateContainer.clear(); // don't restore to the wrong view hierarchy
+ mCurrentLayout = layout;
+ }
+ mKeyguardView = inflateKeyguardView(options, layout);
mKeyguardView.requestFocus();
}
updateUserActivityTimeoutInWindowLayoutParams();
@@ -315,38 +328,24 @@
mKeyguardHost.restoreHierarchyState(mStateContainer);
}
- private void inflateKeyguardView(Bundle options) {
+ private boolean allowNotificationsOnSecureKeyguard() {
+ ContentResolver cr = mContext.getContentResolver();
+ return Settings.Secure.getInt(cr, Settings.Secure.LOCK_SCREEN_ALLOW_NOTIFICATIONS, 0) == 1;
+ }
+
+ private KeyguardViewBase inflateKeyguardView(Bundle options, int layoutId) {
View v = mKeyguardHost.findViewById(R.id.keyguard_host_view);
if (v != null) {
mKeyguardHost.removeView(v);
}
final LayoutInflater inflater = LayoutInflater.from(mContext);
- View view = inflater.inflate(R.layout.keyguard_host_view, mKeyguardHost, true);
- mKeyguardView = (KeyguardHostView) view.findViewById(R.id.keyguard_host_view);
- mKeyguardView.setLockPatternUtils(mLockPatternUtils);
- mKeyguardView.setViewMediatorCallback(mViewMediatorCallback);
- mKeyguardView.initializeSwitchingUserState(options != null &&
- options.getBoolean(IS_SWITCHING_USER));
-
- // HACK
- // The keyguard view will have set up window flags in onFinishInflate before we set
- // the view mediator callback. Make sure it knows the correct IME state.
- if (mViewMediatorCallback != null) {
- KeyguardPasswordView kpv = (KeyguardPasswordView) mKeyguardView.findViewById(
- R.id.keyguard_password_view);
-
- if (kpv != null) {
- mViewMediatorCallback.setNeedsInput(kpv.needsInput());
- }
- }
-
- if (options != null) {
- int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
- AppWidgetManager.INVALID_APPWIDGET_ID);
- if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
- mKeyguardView.goToWidget(widgetToShow);
- }
- }
+ View view = inflater.inflate(layoutId, mKeyguardHost, true);
+ KeyguardViewBase keyguard = (KeyguardViewBase) view.findViewById(R.id.keyguard_host_view);
+ keyguard.setLockPatternUtils(mLockPatternUtils);
+ keyguard.setViewMediatorCallback(mViewMediatorCallback);
+ keyguard.onUserSwitching(options != null && options.getBoolean(IS_SWITCHING_USER));
+ keyguard.onCreateOptions(options);
+ return keyguard;
}
public void updateUserActivityTimeout() {
@@ -541,7 +540,7 @@
public void dispatch(MotionEvent event) {
if (mKeyguardView != null) {
- mKeyguardView.dispatch(event);
+ mKeyguardView.onExternalMotionEvent(event);
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index a7b72e2..e47edf3 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -105,11 +105,6 @@
}
public void showBouncer(boolean show) {
- CharSequence what = mKeyguardHostView.getContext().getResources().getText(
- show ? R.string.keyguard_accessibility_show_bouncer
- : R.string.keyguard_accessibility_hide_bouncer);
- mKeyguardHostView.announceForAccessibility(what);
- mKeyguardHostView.announceCurrentSecurityMethod();
mChallengeLayout.showBouncer();
}
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
index f3b894c..1f39aef 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
@@ -15,6 +15,7 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
@@ -27,6 +28,7 @@
android:layout_height="32dp"
android:padding="3dp"
android:layout_gravity="top|center_horizontal"
+ systemui:frameColor="@color/qs_batterymeter_frame_color"
/>
<TextView
style="@style/TextAppearance.QuickSettings.TileView"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 047570f..734abdc 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -42,7 +42,9 @@
<attr name="decayTime" format="integer" />
<attr name="orientation" />
</declare-styleable>
-
+ <declare-styleable name="BatteryMeterView">
+ <attr name="frameColor" format="color" />
+ </declare-styleable>
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9301618..e525fbb 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -35,6 +35,7 @@
<color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
<color name="batterymeter_charge_color">#FFFFFFFF</color>
<color name="batterymeter_bolt_color">#FFFFFFFF</color>
+ <color name="qs_batterymeter_frame_color">#FF404040</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
<drawable name="notification_item_background_color">#ff111111</drawable>
<drawable name="notification_item_background_color_pressed">#ff454545</drawable>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index eb2c44a..19d06be 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -178,6 +178,10 @@
super(context, attrs, defStyle);
final Resources res = context.getResources();
+ TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
+ defStyle, 0);
+ final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
+ res.getColor(R.color.batterymeter_frame_color));
TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
@@ -189,12 +193,13 @@
}
levels.recycle();
colors.recycle();
+ atts.recycle();
mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
context.getContentResolver(), "status_bar_show_battery_percent", 0);
mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mFramePaint.setColor(res.getColor(R.color.batterymeter_frame_color));
+ mFramePaint.setColor(frameColor);
mFramePaint.setDither(true);
mFramePaint.setStrokeWidth(0);
mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java
index e6a7d76..4f355dd 100644
--- a/policy/src/com/android/internal/policy/impl/PolicyControl.java
+++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java
@@ -140,30 +140,32 @@
sImmersiveStatusFilter = null;
sImmersiveNavigationFilter = null;
sImmersivePreconfirmationsFilter = null;
- String[] nvps = value.split(":");
- for (String nvp : nvps) {
- int i = nvp.indexOf('=');
- if (i == -1) continue;
- String n = nvp.substring(0, i);
- String v = nvp.substring(i + 1);
- if (n.equals(NAME_IMMERSIVE_FULL)) {
- Filter f = Filter.parse(v);
- sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
- if (sImmersivePreconfirmationsFilter == null) {
+ if (value != null) {
+ String[] nvps = value.split(":");
+ for (String nvp : nvps) {
+ int i = nvp.indexOf('=');
+ if (i == -1) continue;
+ String n = nvp.substring(0, i);
+ String v = nvp.substring(i + 1);
+ if (n.equals(NAME_IMMERSIVE_FULL)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
+ if (sImmersivePreconfirmationsFilter == null) {
+ sImmersivePreconfirmationsFilter = f;
+ }
+ } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = f;
+ } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
+ Filter f = Filter.parse(v);
+ sImmersiveNavigationFilter = f;
+ if (sImmersivePreconfirmationsFilter == null) {
+ sImmersivePreconfirmationsFilter = f;
+ }
+ } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
+ Filter f = Filter.parse(v);
sImmersivePreconfirmationsFilter = f;
}
- } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
- Filter f = Filter.parse(v);
- sImmersiveStatusFilter = f;
- } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
- Filter f = Filter.parse(v);
- sImmersiveNavigationFilter = f;
- if (sImmersivePreconfirmationsFilter == null) {
- sImmersivePreconfirmationsFilter = f;
- }
- } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
- Filter f = Filter.parse(v);
- sImmersivePreconfirmationsFilter = f;
}
}
if (DEBUG) {
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index eee4936..842aa23 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -32,7 +32,7 @@
mDestroyed = false;
}
- void setID(int id) {
+ void setID(long id) {
if (mID != 0) {
throw new RSRuntimeException("Internal Error, reset of object ID.");
}
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index f0acb56..4164810 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -136,7 +136,7 @@
return null;
}
- int objectID = rs.nFileA3DGetEntryByIndex(entry.mID, entry.mIndex);
+ long objectID = rs.nFileA3DGetEntryByIndex(entry.mID, entry.mIndex);
if(objectID == 0) {
return null;
}
@@ -292,7 +292,7 @@
long fileId = 0;
if (is instanceof AssetManager.AssetInputStream) {
- int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+ long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
fileId = rs.nFileA3DCreateFromAssetStream(asset);
} else {
throw new RSRuntimeException("Unsupported asset stream");
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 4cd89db..b22aeb7 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -148,7 +148,7 @@
return "DroidSans.ttf";
}
- Font(int id, RenderScript rs) {
+ Font(long id, RenderScript rs) {
super(id, rs);
}
@@ -159,7 +159,7 @@
static public Font createFromFile(RenderScript rs, Resources res, String path, float pointSize) {
rs.validate();
int dpi = res.getDisplayMetrics().densityDpi;
- int fontId = rs.nFontCreateFromFile(path, pointSize, dpi);
+ long fontId = rs.nFontCreateFromFile(path, pointSize, dpi);
if(fontId == 0) {
throw new RSRuntimeException("Unable to create font from file " + path);
@@ -184,7 +184,7 @@
AssetManager mgr = res.getAssets();
int dpi = res.getDisplayMetrics().densityDpi;
- int fontId = rs.nFontCreateFromAsset(mgr, path, pointSize, dpi);
+ long fontId = rs.nFontCreateFromAsset(mgr, path, pointSize, dpi);
if(fontId == 0) {
throw new RSRuntimeException("Unable to create font from asset " + path);
}
@@ -208,9 +208,9 @@
int dpi = res.getDisplayMetrics().densityDpi;
- int fontId = 0;
+ long fontId = 0;
if (is instanceof AssetManager.AssetInputStream) {
- int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+ long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
fontId = rs.nFontCreateFromAssetStream(name, pointSize, dpi, asset);
} else {
throw new RSRuntimeException("Unsupported asset stream created");
diff --git a/rs/java/android/renderscript/Long4.java b/rs/java/android/renderscript/Long4.java
index 757b910..1a1ad74 100644
--- a/rs/java/android/renderscript/Long4.java
+++ b/rs/java/android/renderscript/Long4.java
@@ -505,7 +505,7 @@
* @param data
* @param offset
*/
- public void copyTo(Long[] data, int offset) {
+ public void copyTo(long[] data, int offset) {
data[offset] = (long)(x);
data[offset + 1] = (long)(y);
data[offset + 2] = (long)(z);
diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java
index 730c51b..c0fa9c4 100644
--- a/rs/java/android/renderscript/ProgramStore.java
+++ b/rs/java/android/renderscript/ProgramStore.java
@@ -143,7 +143,7 @@
BlendDstFunc mBlendDst;
boolean mDither;
- ProgramStore(int id, RenderScript rs) {
+ ProgramStore(long id, RenderScript rs) {
super(id, rs);
}
@@ -418,7 +418,7 @@
*/
public ProgramStore create() {
mRS.validate();
- int id = mRS.nProgramStoreCreate(mColorMaskR, mColorMaskG, mColorMaskB, mColorMaskA,
+ long id = mRS.nProgramStoreCreate(mColorMaskR, mColorMaskG, mColorMaskB, mColorMaskA,
mDepthMask, mDither,
mBlendSrc.mID, mBlendDst.mID, mDepthFunc.mID);
ProgramStore programStore = new ProgramStore(id, mRS);
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index b0ef156..a4a9070 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -502,8 +502,8 @@
rsnAllocationResize1D(mContext, id, dimX);
}
- native long rsnFileA3DCreateFromAssetStream(long con, int assetStream);
- synchronized long nFileA3DCreateFromAssetStream(int assetStream) {
+ native long rsnFileA3DCreateFromAssetStream(long con, long assetStream);
+ synchronized long nFileA3DCreateFromAssetStream(long assetStream) {
validate();
return rsnFileA3DCreateFromAssetStream(mContext, assetStream);
}
@@ -527,24 +527,24 @@
validate();
rsnFileA3DGetIndexEntries(mContext, fileA3D, numEntries, IDs, names);
}
- native int rsnFileA3DGetEntryByIndex(long con, long fileA3D, int index);
- synchronized int nFileA3DGetEntryByIndex(long fileA3D, int index) {
+ native long rsnFileA3DGetEntryByIndex(long con, long fileA3D, int index);
+ synchronized long nFileA3DGetEntryByIndex(long fileA3D, int index) {
validate();
return rsnFileA3DGetEntryByIndex(mContext, fileA3D, index);
}
- native int rsnFontCreateFromFile(long con, String fileName, float size, int dpi);
- synchronized int nFontCreateFromFile(String fileName, float size, int dpi) {
+ native long rsnFontCreateFromFile(long con, String fileName, float size, int dpi);
+ synchronized long nFontCreateFromFile(String fileName, float size, int dpi) {
validate();
return rsnFontCreateFromFile(mContext, fileName, size, dpi);
}
- native int rsnFontCreateFromAssetStream(long con, String name, float size, int dpi, int assetStream);
- synchronized int nFontCreateFromAssetStream(String name, float size, int dpi, int assetStream) {
+ native long rsnFontCreateFromAssetStream(long con, String name, float size, int dpi, long assetStream);
+ synchronized long nFontCreateFromAssetStream(String name, float size, int dpi, long assetStream) {
validate();
return rsnFontCreateFromAssetStream(mContext, name, size, dpi, assetStream);
}
- native int rsnFontCreateFromAsset(long con, AssetManager mgr, String path, float size, int dpi);
- synchronized int nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
+ native long rsnFontCreateFromAsset(long con, AssetManager mgr, String path, float size, int dpi);
+ synchronized long nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
validate();
return rsnFontCreateFromAsset(mContext, mgr, path, size, dpi);
}
@@ -661,9 +661,9 @@
rsnScriptSetVarObj(mContext, id, slot, val);
}
- native int rsnScriptCCreate(long con, String resName, String cacheDir,
+ native long rsnScriptCCreate(long con, String resName, String cacheDir,
byte[] script, int length);
- synchronized int nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
+ synchronized long nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
validate();
return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
}
@@ -710,18 +710,18 @@
rsnScriptGroupExecute(mContext, group);
}
- native int rsnSamplerCreate(long con, int magFilter, int minFilter,
+ native long rsnSamplerCreate(long con, int magFilter, int minFilter,
int wrapS, int wrapT, int wrapR, float aniso);
- synchronized int nSamplerCreate(int magFilter, int minFilter,
+ synchronized long nSamplerCreate(int magFilter, int minFilter,
int wrapS, int wrapT, int wrapR, float aniso) {
validate();
return rsnSamplerCreate(mContext, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
}
- native int rsnProgramStoreCreate(long con, boolean r, boolean g, boolean b, boolean a,
+ native long rsnProgramStoreCreate(long con, boolean r, boolean g, boolean b, boolean a,
boolean depthMask, boolean dither,
int srcMode, int dstMode, int depthFunc);
- synchronized int nProgramStoreCreate(boolean r, boolean g, boolean b, boolean a,
+ synchronized long nProgramStoreCreate(boolean r, boolean g, boolean b, boolean a,
boolean depthMask, boolean dither,
int srcMode, int dstMode, int depthFunc) {
validate();
@@ -787,8 +787,8 @@
rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
}
- native long rsnPathCreate(long con, int prim, boolean isStatic, long vtx, int loop, float q);
- synchronized long nPathCreate(int prim, boolean isStatic, long vtx, int loop, float q) {
+ native long rsnPathCreate(long con, int prim, boolean isStatic, long vtx, long loop, float q);
+ synchronized long nPathCreate(int prim, boolean isStatic, long vtx, long loop, float q) {
validate();
return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q);
}
diff --git a/rs/java/android/renderscript/Sampler.java b/rs/java/android/renderscript/Sampler.java
index 39b867b..a4edbb5 100644
--- a/rs/java/android/renderscript/Sampler.java
+++ b/rs/java/android/renderscript/Sampler.java
@@ -49,7 +49,7 @@
Value mWrapR;
float mAniso;
- Sampler(int id, RenderScript rs) {
+ Sampler(long id, RenderScript rs) {
super(id, rs);
}
@@ -336,7 +336,7 @@
public Sampler create() {
mRS.validate();
- int id = mRS.nSamplerCreate(mMag.mID, mMin.mID,
+ long id = mRS.nSamplerCreate(mMag.mID, mMin.mID,
mWrapS.mID, mWrapT.mID, mWrapR.mID, mAniso);
Sampler sampler = new Sampler(id, mRS);
sampler.mMin = mMin;
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index c7979f6..9e76f52 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -38,7 +38,17 @@
protected ScriptC(int id, RenderScript rs) {
super(id, rs);
}
-
+ /**
+ * Only intended for use by the generated derived classes.
+ *
+ * @param id
+ * @param rs
+ *
+ * @hide
+ */
+ protected ScriptC(long id, RenderScript rs) {
+ super(id, rs);
+ }
/**
* Only intended for use by the generated derived classes.
*
@@ -49,7 +59,7 @@
*/
protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
super(0, rs);
- int id = internalCreate(rs, resources, resourceID);
+ long id = internalCreate(rs, resources, resourceID);
if (id == 0) {
throw new RSRuntimeException("Loading of ScriptC script failed.");
}
@@ -63,7 +73,7 @@
static String mCachePath;
- private static synchronized int internalCreate(RenderScript rs, Resources resources, int resourceID) {
+ private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
byte[] pgm;
int pgmLength;
InputStream is = resources.openRawResource(resourceID);
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 024d0c3..80a5da2 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -220,7 +220,7 @@
nDeviceCreate(JNIEnv *_env, jobject _this)
{
LOG_API("nDeviceCreate");
- return (jint)rsDeviceCreate();
+ return (jlong)rsDeviceCreate();
}
static void
@@ -241,17 +241,17 @@
nContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer, jint ct)
{
LOG_API("nContextCreate");
- return (jint)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
+ return (jlong)rsContextCreate((RsDevice)dev, ver, sdkVer, (RsContextType)ct, 0);
}
static jlong
nContextCreateGL(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer,
- int colorMin, int colorPref,
- int alphaMin, int alphaPref,
- int depthMin, int depthPref,
- int stencilMin, int stencilPref,
- int samplesMin, int samplesPref, float samplesQ,
- int dpi)
+ jint colorMin, jint colorPref,
+ jint alphaMin, jint alphaPref,
+ jint depthMin, jint depthPref,
+ jint stencilMin, jint stencilPref,
+ jint samplesMin, jint samplesPref, jfloat samplesQ,
+ jint dpi)
{
RsSurfaceConfig sc;
sc.alphaMin = alphaMin;
@@ -265,7 +265,7 @@
sc.samplesQ = samplesQ;
LOG_API("nContextCreateGL");
- return (jint)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
+ return (jlong)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
}
static void
@@ -355,7 +355,7 @@
ALOGV("message receive buffer too small. %i", receiveLen);
}
_env->ReleaseIntArrayElements(data, ptr, 0);
- return id;
+ return (jint)id;
}
static jint
@@ -370,7 +370,7 @@
auxDataPtr[0] = (jint)subID;
auxDataPtr[1] = (jint)receiveLen;
_env->ReleaseIntArrayElements(auxData, auxDataPtr, 0);
- return id;
+ return (jint)id;
}
static void nContextInitToClient(JNIEnv *_env, jobject _this, jlong con)
@@ -432,7 +432,7 @@
_env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
_env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
- return (jint)id;
+ return (jlong)id;
}
static void
@@ -499,7 +499,7 @@
int elementCount = _env->GetArrayLength(_typeData);
assert(elementCount == 6);
- LOG_API("nTypeCreate, con(%p)", (RsContext)con);
+ LOG_API("nTypeGetNativeData, con(%p)", (RsContext)con);
uint32_t typeData[6];
rsaTypeGetNativeData((RsContext)con, (RsType)id, typeData, 6);
@@ -515,7 +515,7 @@
nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage, jint pointer)
{
LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
- return (jint) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
+ return (jlong) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
}
static void
@@ -662,7 +662,7 @@
static void
nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
- jint count, jobject data, int sizeBytes, int dataType)
+ jint count, jobject data, jint sizeBytes, jint dataType)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)",
@@ -671,8 +671,8 @@
}
static void
-// native void rsnAllocationElementData1D(int con, int id, int xoff, int compIdx, byte[] d, int sizeBytes);
-nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint offset, jint lod, jint compIdx, jbyteArray data, int sizeBytes)
+// native void rsnAllocationElementData1D(long con, long id, int xoff, int compIdx, byte[] d, int sizeBytes);
+nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint offset, jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
{
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
@@ -683,7 +683,7 @@
static void
nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
- jint w, jint h, jobject data, int sizeBytes, int dataType)
+ jint w, jint h, jobject data, jint sizeBytes, jint dataType)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
@@ -797,9 +797,8 @@
static jlong
nFileA3DCreateFromAssetStream(JNIEnv *_env, jobject _this, jlong con, jlong native_asset)
{
- ALOGV("______nFileA3D %u", (uint32_t) native_asset);
-
Asset* asset = reinterpret_cast<Asset*>(native_asset);
+ ALOGV("______nFileA3D %p", asset);
jlong id = (jlong)rsaFileA3DCreateFromMemory((RsContext)con, asset->getBuffer(false), asset->getLength());
return id;
@@ -837,13 +836,13 @@
{
int32_t numEntries = 0;
rsaFileA3DGetNumIndexEntries((RsContext)con, &numEntries, (RsFile)fileA3D);
- return numEntries;
+ return (jint)numEntries;
}
static void
nFileA3DGetIndexEntries(JNIEnv *_env, jobject _this, jlong con, jlong fileA3D, jint numEntries, jintArray _ids, jobjectArray _entries)
{
- ALOGV("______nFileA3D %u", (uint32_t) fileA3D);
+ ALOGV("______nFileA3D %p", (RsFile) fileA3D);
RsFileIndexEntry *fileEntries = (RsFileIndexEntry*)malloc((uint32_t)numEntries * sizeof(RsFileIndexEntry));
rsaFileA3DGetIndexEntries((RsContext)con, fileEntries, (uint32_t)numEntries, (RsFile)fileA3D);
@@ -856,43 +855,43 @@
free(fileEntries);
}
-static int
+static jlong
nFileA3DGetEntryByIndex(JNIEnv *_env, jobject _this, jlong con, jlong fileA3D, jint index)
{
- ALOGV("______nFileA3D %u", (uint32_t) fileA3D);
- jint id = (jint)rsaFileA3DGetEntryByIndex((RsContext)con, (uint32_t)index, (RsFile)fileA3D);
+ ALOGV("______nFileA3D %p", (RsFile) fileA3D);
+ jlong id = (jlong)rsaFileA3DGetEntryByIndex((RsContext)con, (uint32_t)index, (RsFile)fileA3D);
return id;
}
// -----------------------------------
-static int
+static jlong
nFontCreateFromFile(JNIEnv *_env, jobject _this, jlong con,
jstring fileName, jfloat fontSize, jint dpi)
{
AutoJavaStringToUTF8 fileNameUTF(_env, fileName);
- jint id = (jint)rsFontCreateFromFile((RsContext)con,
+ jlong id = (jlong)rsFontCreateFromFile((RsContext)con,
fileNameUTF.c_str(), fileNameUTF.length(),
fontSize, dpi);
return id;
}
-static int
+static jlong
nFontCreateFromAssetStream(JNIEnv *_env, jobject _this, jlong con,
- jstring name, jfloat fontSize, jint dpi, jint native_asset)
+ jstring name, jfloat fontSize, jint dpi, jlong native_asset)
{
Asset* asset = reinterpret_cast<Asset*>(native_asset);
AutoJavaStringToUTF8 nameUTF(_env, name);
- jint id = (jint)rsFontCreateFromMemory((RsContext)con,
+ jlong id = (jlong)rsFontCreateFromMemory((RsContext)con,
nameUTF.c_str(), nameUTF.length(),
fontSize, dpi,
asset->getBuffer(false), asset->getLength());
return id;
}
-static int
+static jlong
nFontCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path,
jfloat fontSize, jint dpi)
{
@@ -907,7 +906,7 @@
return 0;
}
- jint id = (jint)rsFontCreateFromMemory((RsContext)con,
+ jlong id = (jlong)rsFontCreateFromMemory((RsContext)con,
str.c_str(), str.length(),
fontSize, dpi,
asset->getBuffer(false), asset->getLength());
@@ -1126,7 +1125,7 @@
// -----------------------------------
-static jint
+static jlong
nScriptCCreate(JNIEnv *_env, jobject _this, jlong con,
jstring resName, jstring cacheDir,
jbyteArray scriptRef, jint length)
@@ -1135,7 +1134,7 @@
AutoJavaStringToUTF8 resNameUTF(_env, resName);
AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
- jint ret = 0;
+ jlong ret = 0;
jbyte* script_ptr = NULL;
jint _exception = 0;
jint remaining;
@@ -1161,7 +1160,7 @@
//rsScriptCSetText((RsContext)con, (const char *)script_ptr, length);
- ret = (jint)rsScriptCCreate((RsContext)con,
+ ret = (jlong)rsScriptCCreate((RsContext)con,
resNameUTF.c_str(), resNameUTF.length(),
cacheDirUTF.c_str(), cacheDirUTF.length(),
(const char *)script_ptr, length);
@@ -1172,7 +1171,7 @@
_exception ? JNI_ABORT: 0);
}
- return ret;
+ return (jlong)ret;
}
static jlong
@@ -1186,14 +1185,14 @@
nScriptKernelIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jint sig)
{
LOG_API("nScriptKernelIDCreate, con(%p) script(%p), slot(%i), sig(%i)", (RsContext)con, (void *)sid, slot, sig);
- return (jint)rsScriptKernelIDCreate((RsContext)con, (RsScript)sid, slot, sig);
+ return (jlong)rsScriptKernelIDCreate((RsContext)con, (RsScript)sid, slot, sig);
}
static jlong
nScriptFieldIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
{
LOG_API("nScriptFieldIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con, (void *)sid, slot);
- return (jint)rsScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
+ return (jlong)rsScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
}
static jlong
@@ -1253,7 +1252,7 @@
// ---------------------------------------------------------------------------
-static jint
+static jlong
nProgramStoreCreate(JNIEnv *_env, jobject _this, jlong con,
jboolean colorMaskR, jboolean colorMaskG, jboolean colorMaskB, jboolean colorMaskA,
jboolean depthMask, jboolean ditherEnable,
@@ -1261,7 +1260,7 @@
jint depthFunc)
{
LOG_API("nProgramStoreCreate, con(%p)", (RsContext)con);
- return (jint)rsProgramStoreCreate((RsContext)con, colorMaskR, colorMaskG, colorMaskB, colorMaskA,
+ return (jlong)rsProgramStoreCreate((RsContext)con, colorMaskR, colorMaskG, colorMaskB, colorMaskA,
depthMask, ditherEnable, (RsBlendSrcFunc)srcFunc,
(RsBlendDstFunc)destFunc, (RsDepthFunc)depthFunc);
}
@@ -1346,7 +1345,7 @@
nProgramRasterCreate(JNIEnv *_env, jobject _this, jlong con, jboolean pointSprite, jint cull)
{
LOG_API("nProgramRasterCreate, con(%p), pointSprite(%i), cull(%i)", (RsContext)con, pointSprite, cull);
- return (jint)rsProgramRasterCreate((RsContext)con, pointSprite, (RsCullMode)cull);
+ return (jlong)rsProgramRasterCreate((RsContext)con, pointSprite, (RsCullMode)cull);
}
@@ -1390,12 +1389,12 @@
// ---------------------------------------------------------------------------
-static jint
+static jlong
nSamplerCreate(JNIEnv *_env, jobject _this, jlong con, jint magFilter, jint minFilter,
jint wrapS, jint wrapT, jint wrapR, jfloat aniso)
{
LOG_API("nSamplerCreate, con(%p)", (RsContext)con);
- return (jint)rsSamplerCreate((RsContext)con,
+ return (jlong)rsSamplerCreate((RsContext)con,
(RsSamplerValue)magFilter,
(RsSamplerValue)minFilter,
(RsSamplerValue)wrapS,
@@ -1407,7 +1406,7 @@
// ---------------------------------------------------------------------------
static jlong
-nPathCreate(JNIEnv *_env, jobject _this, jlong con, jint prim, jboolean isStatic, jlong _vtx, jint _loop, jfloat q) {
+nPathCreate(JNIEnv *_env, jobject _this, jlong con, jint prim, jboolean isStatic, jlong _vtx, jlong _loop, jfloat q) {
LOG_API("nPathCreate, con(%p)", (RsContext)con);
jlong id = (jlong)rsPathCreate((RsContext)con, (RsPathPrimitive)prim, isStatic,
@@ -1526,15 +1525,15 @@
{"rsnObjDestroy", "(JJ)V", (void*)nObjDestroy },
{"rsnFileA3DCreateFromFile", "(JLjava/lang/String;)J", (void*)nFileA3DCreateFromFile },
-{"rsnFileA3DCreateFromAssetStream", "(JI)J", (void*)nFileA3DCreateFromAssetStream },
+{"rsnFileA3DCreateFromAssetStream", "(JJ)J", (void*)nFileA3DCreateFromAssetStream },
{"rsnFileA3DCreateFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)J", (void*)nFileA3DCreateFromAsset },
{"rsnFileA3DGetNumIndexEntries", "(JJ)I", (void*)nFileA3DGetNumIndexEntries },
{"rsnFileA3DGetIndexEntries", "(JJI[I[Ljava/lang/String;)V", (void*)nFileA3DGetIndexEntries },
-{"rsnFileA3DGetEntryByIndex", "(JJI)I", (void*)nFileA3DGetEntryByIndex },
+{"rsnFileA3DGetEntryByIndex", "(JJI)J", (void*)nFileA3DGetEntryByIndex },
-{"rsnFontCreateFromFile", "(JLjava/lang/String;FI)I", (void*)nFontCreateFromFile },
-{"rsnFontCreateFromAssetStream", "(JLjava/lang/String;FII)I", (void*)nFontCreateFromAssetStream },
-{"rsnFontCreateFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;FI)I", (void*)nFontCreateFromAsset },
+{"rsnFontCreateFromFile", "(JLjava/lang/String;FI)J", (void*)nFontCreateFromFile },
+{"rsnFontCreateFromAssetStream", "(JLjava/lang/String;FIJ)J", (void*)nFontCreateFromAssetStream },
+{"rsnFontCreateFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;FI)J", (void*)nFontCreateFromAsset },
{"rsnElementCreate", "(JJIZI)J", (void*)nElementCreate },
{"rsnElementCreate2", "(J[I[Ljava/lang/String;[I)J", (void*)nElementCreate2 },
@@ -1591,7 +1590,7 @@
{"rsnScriptSetVarVE", "(JJI[BJ[I)V", (void*)nScriptSetVarVE },
{"rsnScriptSetVarObj", "(JJIJ)V", (void*)nScriptSetVarObj },
-{"rsnScriptCCreate", "(JLjava/lang/String;Ljava/lang/String;[BI)I", (void*)nScriptCCreate },
+{"rsnScriptCCreate", "(JLjava/lang/String;Ljava/lang/String;[BI)J", (void*)nScriptCCreate },
{"rsnScriptIntrinsicCreate", "(JIJ)J", (void*)nScriptIntrinsicCreate },
{"rsnScriptKernelIDCreate", "(JJII)J", (void*)nScriptKernelIDCreate },
{"rsnScriptFieldIDCreate", "(JJI)J", (void*)nScriptFieldIDCreate },
@@ -1600,7 +1599,7 @@
{"rsnScriptGroupSetOutput", "(JJJJ)V", (void*)nScriptGroupSetOutput },
{"rsnScriptGroupExecute", "(JJ)V", (void*)nScriptGroupExecute },
-{"rsnProgramStoreCreate", "(JZZZZZZIII)I", (void*)nProgramStoreCreate },
+{"rsnProgramStoreCreate", "(JZZZZZZIII)J", (void*)nProgramStoreCreate },
{"rsnProgramBindConstants", "(JJIJ)V", (void*)nProgramBindConstants },
{"rsnProgramBindTexture", "(JJIJ)V", (void*)nProgramBindTexture },
@@ -1616,9 +1615,9 @@
{"rsnContextBindProgramVertex", "(JI)V", (void*)nContextBindProgramVertex },
{"rsnContextBindProgramRaster", "(JI)V", (void*)nContextBindProgramRaster },
-{"rsnSamplerCreate", "(JIIIIIF)I", (void*)nSamplerCreate },
+{"rsnSamplerCreate", "(JIIIIIF)J", (void*)nSamplerCreate },
-{"rsnPathCreate", "(JIZJIF)J", (void*)nPathCreate },
+{"rsnPathCreate", "(JIZJJF)J", (void*)nPathCreate },
{"rsnMeshCreate", "(J[I[I[I)J", (void*)nMeshCreate },
{"rsnMeshGetVertexBufferCount", "(JJ)I", (void*)nMeshGetVertexBufferCount },
@@ -1648,7 +1647,7 @@
assert(env != NULL);
if (registerFuncs(env) < 0) {
- ALOGE("ERROR: MediaPlayer native registration failed\n");
+ ALOGE("ERROR: Renderscript native registration failed\n");
goto bail;
}
diff --git a/services/Android.mk b/services/Android.mk
index 80fd35a..a8881b6 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -1,27 +1,23 @@
LOCAL_PATH:= $(call my-dir)
-# the java library
+# merge all required services into one jar
# ============================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES :=
+LOCAL_MODULE := services
-# TODO: Move this to the product makefiles
-REQUIRED_SERVICES := core accessibility appwidget backup devicepolicy print
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
-include $(patsubst %,$(LOCAL_PATH)/%/java/service.mk,$(REQUIRED_SERVICES))
-
-LOCAL_MODULE:= services
-
-LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
-
-#LOCAL_PROGUARD_ENABLED := full
-#LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ services.core \
+ services.accessibility \
+ services.appwidget \
+ services.backup \
+ services.devicepolicy \
+ services.print
include $(BUILD_JAVA_LIBRARY)
-include $(BUILD_DROIDDOC)
-
# native library
# =============================================================
diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk
new file mode 100644
index 0000000..d98fc28
--- /dev/null
+++ b/services/accessibility/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.accessibility
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/accessibility/java/service.mk b/services/accessibility/java/service.mk
deleted file mode 100644
index 5e8f375..0000000
--- a/services/accessibility/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring accessibility,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := accessibility/java
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.accessibility.AccessibilityManagerService
-
-endif
diff --git a/services/appwidget/Android.mk b/services/appwidget/Android.mk
new file mode 100644
index 0000000..ca38f2f
--- /dev/null
+++ b/services/appwidget/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.appwidget
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/appwidget/java/service.mk b/services/appwidget/java/service.mk
deleted file mode 100644
index 0e33446..0000000
--- a/services/appwidget/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring appwidget,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := appwidget/java
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.appwidget.AppWidgetService
-
-endif
diff --git a/services/backup/Android.mk b/services/backup/Android.mk
new file mode 100644
index 0000000..3e686d1
--- /dev/null
+++ b/services/backup/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.backup
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/backup/java/service.mk b/services/backup/java/service.mk
deleted file mode 100644
index bd22b95..0000000
--- a/services/backup/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring backup,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := backup/java
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.backup.BackupManagerService
-
-endif
diff --git a/services/core/Android.mk b/services/core/Android.mk
new file mode 100644
index 0000000..5c45201
--- /dev/null
+++ b/services/core/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.core
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java) \
+ java/com/android/server/EventLogTags.logtags \
+ java/com/android/server/am/EventLogTags.logtags
+
+LOCAL_JAVA_LIBRARIES := android.policy telephony-common
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 17bb3e0..be2df04 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -28,6 +28,7 @@
import android.os.Looper;
import android.os.SystemProperties;
import android.util.ArrayMap;
+import com.android.internal.app.ProcessMap;
import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
@@ -595,12 +596,7 @@
break;
}
}
- if (anyForeground != proc.foregroundServices) {
- proc.foregroundServices = anyForeground;
- if (oomAdj) {
- mAm.updateOomAdjLocked();
- }
- }
+ mAm.updateProcessForegroundLocked(proc, anyForeground, oomAdj);
}
private boolean updateServiceClientActivitiesLocked(ProcessRecord proc,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8693c31..8975d12 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -51,7 +51,6 @@
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ServiceThread;
-import com.android.server.SystemServer;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
@@ -922,11 +921,25 @@
long mLowRamTimeSinceLastIdle = 0;
/**
- * If RAM is currently low, when that horrible situatin started.
+ * If RAM is currently low, when that horrible situation started.
*/
long mLowRamStartTime = 0;
/**
+ * For reporting to battery stats the current top application.
+ */
+ private String mCurResumedPackage = null;
+ private int mCurResumedUid = -1;
+
+ /**
+ * For reporting to battery stats the apps currently running foreground
+ * service. The ProcessMap is package/uid tuples; each of these contain
+ * an array of the currently foreground processes.
+ */
+ final ProcessMap<ArrayList<ProcessRecord>> mForegroundPackages
+ = new ProcessMap<ArrayList<ProcessRecord>>();
+
+ /**
* This is set if we had to do a delayed dexopt of an app before launching
* it, to increasing the ANR timeouts in that case.
*/
@@ -2768,7 +2781,7 @@
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
- mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_STARTED,
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_START,
app.processName, app.info.uid);
if (app.isolated) {
mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
@@ -4728,7 +4741,7 @@
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
- mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
app.processName, app.info.uid);
if (app.isolated) {
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -4773,7 +4786,7 @@
mHeavyWeightProcess.userId, 0));
mHeavyWeightProcess = null;
}
- mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
app.processName, app.info.uid);
if (app.isolated) {
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -4862,7 +4875,7 @@
app.curAdj = app.setAdj = -100;
app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground = null;
- app.foregroundServices = false;
+ updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
@@ -5565,7 +5578,7 @@
return;
}
pr.forcingToForeground = null;
- pr.foregroundServices = false;
+ updateProcessForegroundLocked(pr, false, false);
}
updateOomAdjLocked();
}
@@ -12116,7 +12129,25 @@
if (!brief) {
if (!isCompact) {
pw.print("Total RAM: "); pw.print(memInfo.getTotalSizeKb());
- pw.println(" kB");
+ pw.print(" kB (status ");
+ switch (mLastMemoryLevel) {
+ case ProcessStats.ADJ_MEM_FACTOR_NORMAL:
+ pw.println("normal)");
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+ pw.println("moderate)");
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_LOW:
+ pw.println("low)");
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+ pw.println("critical)");
+ break;
+ default:
+ pw.print(mLastMemoryLevel);
+ pw.println(")");
+ break;
+ }
pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
+ memInfo.getFreeSizeKb()); pw.print(" kB (");
pw.print(cachedPss); pw.print(" cached pss + ");
@@ -12331,7 +12362,7 @@
app.unlinkDeathRecipient();
app.makeInactive(mProcessStats);
app.forcingToForeground = null;
- app.foregroundServices = false;
+ updateProcessForegroundLocked(app, false, false);
app.foregroundActivities = false;
app.hasShownUi = false;
app.hasAboveClient = false;
@@ -12465,7 +12496,7 @@
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
- mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISHED,
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_PROC_FINISH,
app.processName, app.info.uid);
if (app.isolated) {
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
@@ -15286,8 +15317,66 @@
reportingProcessState, now);
}
+ final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
+ boolean oomAdj) {
+ if (isForeground != proc.foregroundServices) {
+ proc.foregroundServices = isForeground;
+ ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
+ proc.info.uid);
+ if (isForeground) {
+ if (curProcs == null) {
+ curProcs = new ArrayList<ProcessRecord>();
+ mForegroundPackages.put(proc.info.packageName, proc.info.uid, curProcs);
+ }
+ if (!curProcs.contains(proc)) {
+ curProcs.add(proc);
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_FOREGROUND_START,
+ proc.info.packageName, proc.info.uid);
+ }
+ } else {
+ if (curProcs != null) {
+ if (curProcs.remove(proc)) {
+ mBatteryStatsService.noteEvent(
+ BatteryStats.HistoryItem.EVENT_FOREGROUND_FINISH,
+ proc.info.packageName, proc.info.uid);
+ if (curProcs.size() <= 0) {
+ mForegroundPackages.remove(proc.info.packageName, proc.info.uid);
+ }
+ }
+ }
+ }
+ if (oomAdj) {
+ updateOomAdjLocked();
+ }
+ }
+ }
+
private final ActivityRecord resumedAppLocked() {
- return mStackSupervisor.resumedAppLocked();
+ ActivityRecord act = mStackSupervisor.resumedAppLocked();
+ String pkg;
+ int uid;
+ if (act != null) {
+ pkg = act.packageName;
+ uid = act.info.applicationInfo.uid;
+ } else {
+ pkg = null;
+ uid = -1;
+ }
+ // Has the UID or resumed package name changed?
+ if (uid != mCurResumedUid || (pkg != mCurResumedPackage
+ && (pkg == null || !pkg.equals(mCurResumedPackage)))) {
+ if (mCurResumedPackage != null) {
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_FINISH,
+ mCurResumedPackage, mCurResumedUid);
+ }
+ mCurResumedPackage = pkg;
+ mCurResumedUid = uid;
+ if (mCurResumedPackage != null) {
+ mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_TOP_START,
+ mCurResumedPackage, mCurResumedUid);
+ }
+ }
+ return act;
}
final boolean updateOomAdjLocked(ProcessRecord app) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a33b0e5..8f8b2a2 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1151,7 +1151,11 @@
if (err == ActivityManager.START_SUCCESS) {
final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
- + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+ + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)
+ + " on display " + (container == null ? (mFocusedStack == null ?
+ Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
+ (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+ container.mActivityDisplay.mDisplayId)));
}
ActivityRecord sourceRecord = null;
@@ -3069,10 +3073,6 @@
init(mDisplayManager.getDisplay(displayId));
}
- ActivityDisplay(Display display) {
- init(display);
- }
-
ActivityDisplay(Surface surface, int width, int height, int density) {
DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 62dc090..3d22370 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -78,6 +78,7 @@
synchronized (this) {
if (mColor == 0 && !mFlashing) {
setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
+ mColor = 0;
mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bf8c9da..0862153 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1307,6 +1307,11 @@
// Collect all vendor packages.
File vendorAppDir = new File("/vendor/app");
+ try {
+ vendorAppDir = vendorAppDir.getCanonicalFile();
+ } catch (IOException e) {
+ // failed to look up canonical path, continue with original one
+ }
mVendorInstallObserver = new AppDirObserver(
vendorAppDir.getPath(), OBSERVER_EVENTS, true, false);
mVendorInstallObserver.startWatching();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e98014b..ca4ad8a 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -105,6 +105,8 @@
// Input application handle used by the input dispatcher.
final InputApplicationHandle mInputApplicationHandle;
+ boolean mDeferRemoval;
+
AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
super(_service, _token.asBinder(),
WindowManager.LayoutParams.TYPE_APPLICATION, true);
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 30eaf45..574ae2d 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -170,7 +170,7 @@
dw = mBounds.width();
dh = mBounds.height();
xPos = mBounds.left;
- yPos = mBounds.right;
+ yPos = mBounds.top;
} else {
// Set surface size to screen size.
final DisplayInfo info = mDisplayContent.getDisplayInfo();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9f45e88..415a06b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -22,12 +22,10 @@
import android.graphics.Rect;
import android.graphics.Region;
-import android.util.EventLog;
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
-import com.android.server.EventLogTags;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -49,7 +47,7 @@
/** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
* from mDisplayWindows; */
- private WindowList mWindows = new WindowList();
+ private final WindowList mWindows = new WindowList();
// This protects the following display size properties, so that
// getDisplaySize() doesn't need to acquire the global lock. This is
@@ -79,21 +77,12 @@
int pendingLayoutChanges;
final boolean isDefaultDisplay;
- /**
- * Window tokens that are in the process of exiting, but still
- * on screen for animations.
- */
+ /** Window tokens that are in the process of exiting, but still on screen for animations. */
final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
- /**
- * Application tokens that are in the process of exiting, but still
- * on screen for animations.
- */
- final AppTokenList mExitingAppTokens = new AppTokenList();
-
/** Array containing all TaskStacks on this display. Array
* is stored in display order with the current bottom stack at 0. */
- private ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
+ private final ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
/** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
* (except a future lockscreen TaskStack) moves to the top. */
@@ -105,14 +94,18 @@
/** Detect user tapping outside of current focused stack bounds .*/
Region mTouchExcludeRegion = new Region();
- /** Save allocating when retrieving tasks */
- private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
-
/** Save allocating when calculating rects */
Rect mTmpRect = new Rect();
+ /** For gathering Task objects in order. */
+ final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
+
final WindowManagerService mService;
+ static final int DEFER_DETACH = 1;
+ static final int DEFER_REMOVAL = 2;
+ int mDeferredActions;
+
/**
* @param display May not be null.
* @param service You know.
@@ -152,41 +145,21 @@
return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
}
+ ArrayList<TaskStack> getStacks() {
+ return mStacks;
+ }
+
/**
* Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
* @return All the Tasks, in order, on this display.
*/
ArrayList<Task> getTasks() {
- return mTaskHistory;
- }
-
- void addTask(Task task, boolean toTop) {
- mTaskHistory.remove(task);
-
- final int userId = task.mUserId;
- int taskNdx;
- final int numTasks = mTaskHistory.size();
- if (toTop) {
- for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
- if (mTaskHistory.get(taskNdx).mUserId == userId) {
- break;
- }
- }
- ++taskNdx;
- } else {
- for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
- if (mTaskHistory.get(taskNdx).mUserId == userId) {
- break;
- }
- }
+ mTmpTaskHistory.clear();
+ final int numStacks = mStacks.size();
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
}
-
- mTaskHistory.add(taskNdx, task);
- EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
- }
-
- void removeTask(Task task) {
- mTaskHistory.remove(task);
+ return mTmpTaskHistory;
}
TaskStack getHomeStack() {
@@ -226,15 +199,6 @@
out.set(left, top, left + width, top + height);
}
- /** @return The number of tokens in all of the Tasks on this display. */
- int numTokens() {
- int count = 0;
- for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- count += mTaskHistory.get(taskNdx).mAppTokens.size();
- }
- return count;
- }
-
/** Refer to {@link WindowManagerService#attachStack(int, int)} */
void attachStack(TaskStack stack) {
if (stack.mStackId == HOME_STACK_ID) {
@@ -253,13 +217,6 @@
}
void detachStack(TaskStack stack) {
- for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = mTaskHistory.get(taskNdx);
- if (task.mStack == stack) {
- mService.tmpRemoveTaskWindowsLocked(task);
- mTaskHistory.remove(taskNdx);
- }
- }
mStacks.remove(stack);
}
@@ -271,17 +228,6 @@
mContentRect.set(contentRect);
}
- boolean getStackBounds(int stackId, Rect bounds) {
- for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mStacks.get(stackNdx);
- if (stackId == stack.mStackId) {
- bounds.set(stack.mBounds);
- return true;
- }
- }
- return false;
- }
-
int stackIdFromPoint(int x, int y) {
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mStacks.get(stackNdx);
@@ -307,7 +253,7 @@
}
}
- void switchUserStacks(int oldUserId, int newUserId) {
+ void switchUserStacks(int newUserId) {
final WindowList windows = getWindowList();
for (int i = 0; i < windows.size(); i++) {
final WindowState win = windows.get(i);
@@ -393,22 +339,27 @@
pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
stack.dump(prefix + " ", pw);
}
- int ndx = numTokens();
- if (ndx > 0) {
- pw.println();
- pw.println(" Application tokens in Z order:");
- getTasks();
- for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
+ pw.println();
+ pw.println(" Application tokens in bottom up Z order:");
+ int ndx = 0;
+ final int numStacks = mStacks.size();
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
final AppWindowToken wtoken = tokens.get(tokenNdx);
- pw.print(" App #"); pw.print(ndx--);
+ pw.print(" App #"); pw.print(ndx++);
pw.print(' '); pw.print(wtoken); pw.println(":");
wtoken.dump(pw, " ");
}
}
}
- if (mExitingTokens.size() > 0) {
+ if (ndx == 0) {
+ pw.println(" None");
+ }
+ pw.println();
+ if (!mExitingTokens.isEmpty()) {
pw.println();
pw.println(" Exiting tokens:");
for (int i=mExitingTokens.size()-1; i>=0; i--) {
@@ -419,17 +370,6 @@
token.dump(pw, " ");
}
}
- if (mExitingAppTokens.size() > 0) {
- pw.println();
- pw.println(" Exiting application tokens:");
- for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
- WindowToken token = mExitingAppTokens.get(i);
- pw.print(" Exiting App #"); pw.print(i);
- pw.print(' '); pw.print(token);
- pw.println(':');
- token.dump(pw, " ");
- }
- }
pw.println();
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 44f2596..c301ffe 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -24,6 +24,7 @@
final AppTokenList mAppTokens = new AppTokenList();
final int taskId;
final int mUserId;
+ boolean mDeferRemoval = false;
Task(AppWindowToken wtoken, TaskStack stack, int userId) {
taskId = wtoken.groupId;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1ada6c2..7d8cff4 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -67,6 +67,9 @@
* then stop any dimming. */
boolean mDimmingTag;
+ /** Application tokens that are exiting, but still on screen for animations. */
+ final AppTokenList mExitingAppTokens = new AppTokenList();
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
@@ -134,6 +137,21 @@
return mBounds.isEmpty();
}
+ boolean isAnimating() {
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ if (windows.get(winNdx).mWinAnimator.isAnimating()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
void resizeBounds(float oldWidth, float oldHeight, float newWidth, float newHeight) {
if (oldWidth == newWidth && oldHeight == newHeight) {
return;
@@ -174,8 +192,8 @@
mTasks.add(stackNdx, task);
task.mStack = this;
- mDisplayContent.addTask(task, toTop);
mDisplayContent.moveStack(this, true);
+ EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, stackNdx);
}
void moveTaskToTop(Task task) {
@@ -200,7 +218,6 @@
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
mTasks.remove(task);
if (mDisplayContent != null) {
- mDisplayContent.removeTask(task);
if (mTasks.isEmpty()) {
mDisplayContent.moveStack(this, false);
}
@@ -216,15 +233,13 @@
mDisplayContent = displayContent;
mDimLayer = new DimLayer(mService, this, displayContent);
mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
-
- for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
- Task task = mTasks.get(taskNdx);
- displayContent.addTask(task, true);
- }
}
- void detach() {
+ void detachDisplay() {
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx));
+ }
mAnimationBackgroundSurface.destroySurface();
mAnimationBackgroundSurface = null;
mDimLayer.destroySurface();
@@ -351,6 +366,34 @@
mAnimationBackgroundSurface.mDimSurface.destroy();
}
+ void checkForDeferredActions() {
+ if (mDisplayContent != null &&
+ (mDisplayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0 &&
+ !isAnimating()) {
+ mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_DETACH;
+ mService.detachStack(mStackId);
+ if ((mDisplayContent.mDeferredActions & DisplayContent.DEFER_REMOVAL) != 0) {
+ mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_REMOVAL;
+ mService.onDisplayRemoved(mDisplayContent.getDisplayId());
+ }
+ }
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = mTasks.get(taskNdx);
+ AppTokenList tokens = task.mAppTokens;
+ for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+ AppWindowToken wtoken = tokens.get(tokenNdx);
+ if (wtoken.mDeferRemoval) {
+ wtoken.mDeferRemoval = false;
+ mService.removeAppFromTaskLocked(wtoken);
+ }
+ }
+ if (task.mDeferRemoval) {
+ task.mDeferRemoval = false;
+ mService.removeTaskLocked(task);
+ }
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
@@ -365,6 +408,17 @@
mDimLayer.printTo(prefix, pw);
pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
}
+ if (!mExitingAppTokens.isEmpty()) {
+ pw.println();
+ pw.println(" Exiting application tokens:");
+ for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
+ WindowToken token = mExitingAppTokens.get(i);
+ pw.print(" Exiting App #"); pw.print(i);
+ pw.print(' '); pw.print(token);
+ pw.println(':');
+ token.dump(pw, " ");
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b4285c6..a9947c0 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -64,7 +64,7 @@
Object mLastWindowFreezeSource;
SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
- new SparseArray<WindowAnimator.DisplayContentsAnimator>(2);
+ new SparseArray<DisplayContentsAnimator>(2);
boolean mInitialized = false;
@@ -151,14 +151,33 @@
}
private void updateAppWindowsLocked(int displayId) {
- final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
- final ArrayList<Task> tasks = displayContent.getTasks();
- final int numTasks = tasks.size();
- for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
- final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- final int numTokens = tokens.size();
- for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
- final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
+ ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = stacks.get(stackNdx);
+ final ArrayList<Task> tasks = stack.getTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+ for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+ final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
+ final boolean wasAnimating = appAnimator.animation != null
+ && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
+ if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+ mAnimating = true;
+ } else if (wasAnimating) {
+ // stopped animating, do one more pass through the layout
+ setAppLayoutChanges(appAnimator,
+ WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+ "appToken " + appAnimator.mAppToken + " done");
+ if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
+ "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+ }
+ }
+ }
+
+ final AppTokenList exitingAppTokens = stack.mExitingAppTokens;
+ final int NEAT = exitingAppTokens.size();
+ for (int i = 0; i < NEAT; i++) {
+ final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
final boolean wasAnimating = appAnimator.animation != null
&& appAnimator.animation != AppWindowAnimator.sDummyAnimation;
if (appAnimator.stepAnimationLocked(mCurrentTime)) {
@@ -166,29 +185,12 @@
} else if (wasAnimating) {
// stopped animating, do one more pass through the layout
setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
- "appToken " + appAnimator.mAppToken + " done");
+ "exiting appToken " + appAnimator.mAppToken + " done");
if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
- "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+ "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
}
}
}
-
- final AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
- final int NEAT = exitingAppTokens.size();
- for (int i = 0; i < NEAT; i++) {
- final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
- final boolean wasAnimating = appAnimator.animation != null
- && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
- if (appAnimator.stepAnimationLocked(mCurrentTime)) {
- mAnimating = true;
- } else if (wasAnimating) {
- // stopped animating, do one more pass through the layout
- setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
- "exiting appToken " + appAnimator.mAppToken + " done");
- if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
- "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
- }
- }
}
private void updateWindowsLocked(final int displayId) {
@@ -449,11 +451,6 @@
}
}
- private void performAnimationsLocked(final int displayId) {
- updateWindowsLocked(displayId);
- updateWallpaperLocked(displayId);
- }
-
/** Locked on mService.mWindowMap. */
private void animateLocked() {
@@ -494,7 +491,8 @@
// Update animations of all applications, including those
// associated with exiting/removed apps
- performAnimationsLocked(displayId);
+ updateWindowsLocked(displayId);
+ updateWallpaperLocked(displayId);
final WindowList windows = mService.getWindowListLocked(displayId);
final int N = windows.size();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5387436..7293d6f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import android.app.AppOpsManager;
+import android.util.ArraySet;
import android.util.TimeUtils;
import android.view.IWindowId;
@@ -363,6 +364,11 @@
final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
/**
+ * Stacks whose animations have ended and whose tasks, apps, selves may now be removed.
+ */
+ final ArraySet<TaskStack> mPendingStacksRemove = new ArraySet<TaskStack>();
+
+ /**
* Used when processing mPendingRemove to avoid working on the original array.
*/
WindowState[] mPendingRemoveTmp = new WindowState[20];
@@ -602,6 +608,9 @@
final WindowAnimator mAnimator;
SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
+
+ /** All of the TaskStacks in the window manager, unordered. For an ordered list call
+ * DisplayContent.getStacks(). */
SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
private final PointerEventDispatcher mPointerEventDispatcher;
@@ -3422,6 +3431,8 @@
}
private Task createTask(int taskId, int stackId, int userId, AppWindowToken atoken) {
+ if (DEBUG_STACK) Slog.i(TAG, "createTask: taskId=" + taskId + " stackId=" + stackId
+ + " atoken=" + atoken);
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
@@ -3504,7 +3515,7 @@
return;
}
final Task oldTask = mTaskIdToTask.get(atoken.groupId);
- removeAppFromTask(atoken);
+ removeAppFromTaskLocked(atoken);
atoken.groupId = groupId;
Task newTask = mTaskIdToTask.get(groupId);
@@ -4522,11 +4533,10 @@
}
}
- void removeAppFromTask(AppWindowToken wtoken) {
+ void removeAppFromTaskLocked(AppWindowToken wtoken) {
final Task task = mTaskIdToTask.get(wtoken.groupId);
- if (task != null && task.removeAppToken(wtoken)) {
- task.mStack.removeTask(task);
- mTaskIdToTask.delete(wtoken.groupId);
+ if (!wtoken.mDeferRemoval && task != null && task.removeAppToken(wtoken)) {
+ removeTaskLocked(task);
}
}
@@ -4562,24 +4572,24 @@
TAG, "Removing app " + wtoken + " delayed=" + delayed
+ " animation=" + wtoken.mAppAnimator.animation
+ " animating=" + wtoken.mAppAnimator.animating);
- final Task task = mTaskIdToTask.get(wtoken.groupId);
- DisplayContent displayContent = task.getDisplayContent();
- if (displayContent != null && delayed) {
+ final TaskStack stack = mTaskIdToTask.get(wtoken.groupId).mStack;
+ if (delayed) {
// set the token aside because it has an active animation to be finished
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"removeAppToken make exiting: " + wtoken);
- displayContent.mExitingAppTokens.add(wtoken);
+ stack.mExitingAppTokens.add(wtoken);
+ wtoken.mDeferRemoval = true;
} else {
// Make sure there is no animation running on this token,
// so any windows associated with it will be removed as
// soon as their animations are complete
wtoken.mAppAnimator.clearAnimation();
wtoken.mAppAnimator.animating = false;
+ removeAppFromTaskLocked(wtoken);
}
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"removeAppToken: " + wtoken);
- removeAppFromTask(wtoken);
wtoken.removed = true;
if (wtoken.startingData != null) {
@@ -4639,17 +4649,19 @@
}
void dumpAppTokensLocked() {
- final int numDisplays = mDisplayContents.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
- Slog.v(TAG, " Display " + displayContent.getDisplayId());
- final ArrayList<Task> tasks = displayContent.getTasks();
- int i = displayContent.numTokens();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
- final AppWindowToken wtoken = tokens.get(tokenNdx);
- Slog.v(TAG, " #" + --i + ": " + wtoken.token);
+ final int numStacks = mStackIdToStack.size();
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
+ Slog.v(TAG, " Stack #" + stack.mStackId + " tasks from bottom to top:");
+ final ArrayList<Task> tasks = stack.getTasks();
+ final int numTasks = tasks.size();
+ for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+ final Task task = tasks.get(taskNdx);
+ Slog.v(TAG, " Task #" + task.taskId + " activities from bottom to top:");
+ AppTokenList tokens = task.mAppTokens;
+ final int numTokens = tokens.size();
+ for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+ Slog.v(TAG, " activity #" + tokenNdx + ": " + tokens.get(tokenNdx).token);
}
}
}
@@ -4911,13 +4923,32 @@
if (stack != null) {
final DisplayContent displayContent = stack.getDisplayContent();
if (displayContent != null) {
+ if (stack.isAnimating()) {
+ displayContent.mDeferredActions |= DisplayContent.DEFER_DETACH;
+ return;
+ }
displayContent.detachStack(stack);
- stack.detach();
+ stack.detachDisplay();
}
}
}
}
+ void removeTaskLocked(Task task) {
+ final int taskId = task.taskId;
+ final TaskStack stack = task.mStack;
+ if (stack.isAnimating()) {
+ if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + taskId);
+ task.mDeferRemoval = true;
+ return;
+ }
+ if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId);
+ EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
+ task.mDeferRemoval = false;
+ task.mStack.removeTask(task);
+ mTaskIdToTask.delete(task.taskId);
+ }
+
public void removeTask(int taskId) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
@@ -4925,14 +4956,14 @@
if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId);
return;
}
- final TaskStack stack = task.mStack;
- EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
- stack.removeTask(task);
+ removeTaskLocked(task);
}
}
public void addTask(int taskId, int stackId, boolean toTop) {
synchronized (mWindowMap) {
+ if (DEBUG_STACK) Slog.i(TAG, "addTask: adding taskId=" + taskId
+ + " to " + (toTop ? "top" : "bottom"));
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
return;
@@ -5241,7 +5272,7 @@
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
- displayContent.switchUserStacks(oldUserId, newUserId);
+ displayContent.switchUserStacks(newUserId);
rebuildAppWindowListLocked(displayContent);
}
performLayoutAndPlaceSurfacesLocked();
@@ -7394,15 +7425,18 @@
case APP_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
Slog.w(TAG, "App freeze timeout expired.");
- DisplayContent displayContent = getDefaultDisplayContentLocked();
- final ArrayList<Task> tasks = displayContent.getTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
- AppWindowToken tok = tokens.get(tokenNdx);
- if (tok.mAppAnimator.freezingScreen) {
- Slog.w(TAG, "Force clearing freeze: " + tok);
- unsetAppFreezingScreenLocked(tok, true, true);
+ final int numStacks = mStackIdToStack.size();
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
+ final ArrayList<Task> tasks = stack.getTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+ for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+ AppWindowToken tok = tokens.get(tokenNdx);
+ if (tok.mAppAnimator.freezingScreen) {
+ Slog.w(TAG, "Force clearing freeze: " + tok);
+ unsetAppFreezingScreenLocked(tok, true, true);
+ }
}
}
}
@@ -8012,21 +8046,27 @@
// in the main app list, but still have windows shown. We put them
// in the back because now that the animation is over we no longer
// will care about them.
- AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
- int NT = exitingAppTokens.size();
- for (int j=0; j<NT; j++) {
- i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
+ final ArrayList<TaskStack> stacks = displayContent.getStacks();
+ final int numStacks = stacks.size();
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens;
+ int NT = exitingAppTokens.size();
+ for (int j = 0; j < NT; j++) {
+ i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
+ }
}
// And add in the still active app tokens in Z order.
- final ArrayList<Task> tasks = displayContent.getTasks();
- final int numTasks = tasks.size();
- for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
- final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- final int numTokens = tokens.size();
- for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
- final AppWindowToken wtoken = tokens.get(tokenNdx);
- i = reAddAppWindowsLocked(displayContent, i, wtoken);
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+ final int numTasks = tasks.size();
+ for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+ final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+ final int numTokens = tokens.size();
+ for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+ final AppWindowToken wtoken = tokens.get(tokenNdx);
+ i = reAddAppWindowsLocked(displayContent, i, wtoken);
+ }
}
}
@@ -8701,15 +8741,14 @@
mAppTransition.setIdle();
// Restore window app tokens to the ActivityManager views
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final ArrayList<Task> tasks = displayContent.getTasks();
- final int numTasks = tasks.size();
- for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
- final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- final int numTokens = tokens.size();
- for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
- final AppWindowToken wtoken = tokens.get(tokenNdx);
- wtoken.sendingToBottom = false;
+ ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+ for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+ tokens.get(tokenNdx).sendingToBottom = false;
+ }
}
}
rebuildAppWindowListLocked();
@@ -8863,7 +8902,7 @@
}
}
- private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) {
+ private void handleFlagDimBehind(WindowState w) {
final WindowManager.LayoutParams attrs = w.mAttrs;
if ((attrs.flags & FLAG_DIM_BEHIND) != 0
&& w.isDisplayedLw()
@@ -8881,22 +8920,23 @@
private void updateAllDrawnLocked(DisplayContent displayContent) {
// See if any windows have been drawn, so they (and others
// associated with them) can now be shown.
- final ArrayList<Task> tasks = displayContent.getTasks();
- final int numTasks = tasks.size();
- for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
- final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- final int numTokens = tokens.size();
- for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
- final AppWindowToken wtoken = tokens.get(tokenNdx);
- if (!wtoken.allDrawn) {
- int numInteresting = wtoken.numInterestingWindows;
- if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
- if (DEBUG_VISIBILITY) Slog.v(TAG,
- "allDrawn: " + wtoken
- + " interesting=" + numInteresting
- + " drawn=" + wtoken.numDrawnWindows);
- wtoken.allDrawn = true;
- mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
+ ArrayList<TaskStack> stacks = displayContent.getStacks();
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+ for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+ final AppWindowToken wtoken = tokens.get(tokenNdx);
+ if (!wtoken.allDrawn) {
+ int numInteresting = wtoken.numInterestingWindows;
+ if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
+ "allDrawn: " + wtoken
+ + " interesting=" + numInteresting
+ + " drawn=" + wtoken.numDrawnWindows);
+ wtoken.allDrawn = true;
+ mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
+ }
}
}
}
@@ -8927,10 +8967,14 @@
for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
displayContent.mExitingTokens.get(i).hasVisible = false;
}
+ }
+ for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
// Initialize state of exiting applications.
- for (i=displayContent.mExitingAppTokens.size()-1; i>=0; i--) {
- displayContent.mExitingAppTokens.get(i).hasVisible = false;
+ final AppTokenList exitingAppTokens =
+ mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+ for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+ exitingAppTokens.get(tokenNdx).hasVisible = false;
}
}
@@ -9063,7 +9107,7 @@
}
if (!stack.testDimmingTag()) {
- handleFlagDimBehind(w, innerDw, innerDh);
+ handleFlagDimBehind(w);
}
if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
@@ -9279,22 +9323,6 @@
// Don't remove this window until rotation has completed.
continue;
}
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Reporting new frame to " + win + ": " + win.mCompatFrame);
- int diff = 0;
- boolean configChanged = win.isConfigChanged();
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
- && configChanged) {
- Slog.i(TAG, "Sending new config to window " + win + ": "
- + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
- + " / " + mCurConfiguration + " / 0x"
- + Integer.toHexString(diff));
- }
- win.setConfiguration(mCurConfiguration);
- if (DEBUG_ORIENTATION &&
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
- TAG, "Resizing " + win + " WITH DRAW PENDING");
win.reportResized();
mResizingWindows.remove(i);
}
@@ -9343,9 +9371,13 @@
}
}
}
+ }
- // Time to remove any exiting applications?
- AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+ // Time to remove any exiting applications?
+ for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+ // Initialize state of exiting applications.
+ final AppTokenList exitingAppTokens =
+ mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
AppWindowToken token = exitingAppTokens.get(i);
if (!token.hasVisible && !mClosingApps.contains(token)) {
@@ -9356,7 +9388,7 @@
token.mAppAnimator.animating = false;
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
"performLayout: App token exiting now removed" + token);
- removeAppFromTask(token);
+ removeAppFromTaskLocked(token);
exitingAppTokens.remove(i);
}
}
@@ -9449,6 +9481,11 @@
}
}
+ // Remove all deferred Stacks, tasks, and activities.
+ for (int stackNdx = mPendingStacksRemove.size() - 1; stackNdx >= 0; --stackNdx) {
+ mPendingStacksRemove.removeAt(stackNdx).checkForDeferredActions();
+ }
+
setFocusedStackFrame();
// Check to see if we are now in a state where the screen should
@@ -10831,6 +10868,10 @@
private void handleDisplayRemovedLocked(int displayId) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
+ if ((displayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0) {
+ displayContent.mDeferredActions |= DisplayContent.DEFER_REMOVAL;
+ return;
+ }
mDisplayContents.delete(displayId);
displayContent.close();
if (displayId == Display.DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2f778b1..a8e45c4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,8 +16,11 @@
package com.android.server.wm;
-import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -1310,13 +1313,24 @@
void reportResized() {
try {
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
+ + ": " + mCompatFrame);
+ boolean configChanged = isConfigChanged();
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
+ Slog.i(TAG, "Sending new config to window " + this + ": "
+ + mWinAnimator.mSurfaceW + "x" + mWinAnimator.mSurfaceH
+ + " / " + mService.mCurConfiguration);
+ }
+ setConfiguration(mService.mCurConfiguration);
+ if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
+ Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
+
final Rect frame = mFrame;
final Rect overscanInsets = mLastOverscanInsets;
final Rect contentInsets = mLastContentInsets;
final Rect visibleInsets = mLastVisibleInsets;
- final boolean reportDraw
- = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
- final Configuration newConfig = isConfigChanged() ? mConfiguration : null;
+ final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
+ final Configuration newConfig = configChanged ? mConfiguration : null;
if (mClient instanceof IWindow.Stub) {
// To prevent deadlock simulate one-way call if win.mClient is a local object.
mService.mH.post(new Runnable() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 76e885f..ffb17f1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -416,6 +416,7 @@
mService.mPendingRemove.add(mWin);
mWin.mRemoveOnExit = false;
}
+ mService.mPendingStacksRemove.add(mWin.getStack());
mAnimator.hideWallpapersLocked(mWin);
}
diff --git a/services/core/java/service.mk b/services/core/java/service.mk
deleted file mode 100644
index 4cb411b..0000000
--- a/services/core/java/service.mk
+++ /dev/null
@@ -1,6 +0,0 @@
-SUB_DIR := core/java
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,$(SUB_DIR)) \
- $(SUB_DIR)/com/android/server/EventLogTags.logtags \
- $(SUB_DIR)/com/android/server/am/EventLogTags.logtags
diff --git a/services/devicepolicy/Android.mk b/services/devicepolicy/Android.mk
new file mode 100644
index 0000000..a55d138
--- /dev/null
+++ b/services/devicepolicy/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.devicepolicy
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := conscrypt
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
new file mode 100644
index 0000000..1b048a1
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.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 com.android.server.devicepolicy;
+
+import android.app.AppGlobals;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+
+/**
+ * Stores and restores state for the Device and Profile owners. By definition there can be
+ * only one device owner, but there may be a profile owner for each user.
+ */
+public class DeviceOwner {
+ private static final String TAG = "DevicePolicyManagerService";
+
+ private static final String DEVICE_OWNER_XML = "device_owner.xml";
+ private static final String TAG_DEVICE_OWNER = "device-owner";
+ private static final String TAG_PROFILE_OWNER = "profile-owner";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_PACKAGE = "package";
+ private static final String ATTR_USERID = "userId";
+
+ private AtomicFile fileForWriting;
+
+ // Input/Output streams for testing.
+ private InputStream mInputStreamForTest;
+ private OutputStream mOutputStreamForTest;
+
+ // Internal state for the device owner package.
+ private String mDeviceOwnerPackageName;
+ private String mDeviceOwnerName;
+
+ // Internal state for the profile owner packages.
+ private final HashMap<Integer, String[]> mProfileOwners = new HashMap<Integer, String[]>();
+
+ // Private default constructor.
+ private DeviceOwner() {
+ }
+
+ @VisibleForTesting
+ DeviceOwner(InputStream in, OutputStream out) {
+ mInputStreamForTest = in;
+ mOutputStreamForTest = out;
+ }
+
+ /**
+ * Loads the device owner state from disk.
+ */
+ static DeviceOwner load() {
+ DeviceOwner owner = new DeviceOwner();
+ if (new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML).exists()) {
+ owner.readOwnerFile();
+ return owner;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Creates an instance of the device owner object with the device owner set.
+ */
+ static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
+ DeviceOwner owner = new DeviceOwner();
+ owner.mDeviceOwnerPackageName = packageName;
+ owner.mDeviceOwnerName = ownerName;
+ return owner;
+ }
+
+ /**
+ * Creates an instance of the device owner object with the profile owner set.
+ */
+ static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
+ DeviceOwner owner = new DeviceOwner();
+ owner.mProfileOwners.put(userId, new String[] { packageName, ownerName });
+ return owner;
+ }
+
+ String getDeviceOwnerPackageName() {
+ return mDeviceOwnerPackageName;
+ }
+
+ String getDeviceOwnerName() {
+ return mDeviceOwnerName;
+ }
+
+ void setDeviceOwner(String packageName, String ownerName) {
+ mDeviceOwnerPackageName = packageName;
+ mDeviceOwnerName = ownerName;
+ }
+
+ void setProfileOwner(String packageName, String ownerName, int userId) {
+ mProfileOwners.put(userId, new String[] { packageName, ownerName });
+ }
+
+ void removeProfileOwner(int userId) {
+ mProfileOwners.remove(userId);
+ }
+
+ String getProfileOwnerPackageName(int userId) {
+ String[] profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner[0] : null;
+ }
+
+ String getProfileOwnerName(int userId) {
+ String[] profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner[1] : null;
+ }
+
+ boolean hasDeviceOwner() {
+ return mDeviceOwnerPackageName != null;
+ }
+
+ static boolean isInstalled(String packageName, PackageManager pm) {
+ try {
+ PackageInfo pi;
+ if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
+ if ((pi.applicationInfo.flags) != 0) {
+ return true;
+ }
+ }
+ } catch (NameNotFoundException nnfe) {
+ Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+ }
+ return false;
+ }
+
+ static boolean isInstalledForUser(String packageName, int userHandle) {
+ try {
+ PackageInfo pi = (AppGlobals.getPackageManager())
+ .getPackageInfo(packageName, 0, userHandle);
+ if (pi != null && pi.applicationInfo.flags != 0) {
+ return true;
+ }
+ } catch (RemoteException re) {
+ throw new RuntimeException("Package manager has died", re);
+ }
+
+ return false;
+ }
+
+ void readOwnerFile() {
+ try {
+ InputStream input = openRead();
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(input, null);
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type!=XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String tag = parser.getName();
+ if (tag.equals(TAG_DEVICE_OWNER)) {
+ mDeviceOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ mDeviceOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+ } else if (tag.equals(TAG_PROFILE_OWNER)) {
+ String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+ int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
+ mProfileOwners.put(userId,
+ new String[] { profileOwnerPackageName, profileOwnerName });
+ } else {
+ throw new XmlPullParserException(
+ "Unexpected tag in device owner file: " + tag);
+ }
+ }
+ input.close();
+ } catch (XmlPullParserException xppe) {
+ Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+ } catch (IOException ioe) {
+ Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+ }
+ }
+
+ void writeOwnerFile() {
+ synchronized (this) {
+ writeOwnerFileLocked();
+ }
+ }
+
+ private void writeOwnerFileLocked() {
+ try {
+ OutputStream outputStream = startWrite();
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(outputStream, "utf-8");
+ out.startDocument(null, true);
+
+ // Write device owner tag
+ if (mDeviceOwnerPackageName != null) {
+ out.startTag(null, TAG_DEVICE_OWNER);
+ out.attribute(null, ATTR_PACKAGE, mDeviceOwnerPackageName);
+ if (mDeviceOwnerName != null) {
+ out.attribute(null, ATTR_NAME, mDeviceOwnerName);
+ }
+ out.endTag(null, TAG_DEVICE_OWNER);
+ }
+
+ // Write profile owner tags
+ if (mProfileOwners.size() > 0) {
+ for (HashMap.Entry<Integer, String[]> owner : mProfileOwners.entrySet()) {
+ out.startTag(null, TAG_PROFILE_OWNER);
+ out.attribute(null, ATTR_PACKAGE, owner.getValue()[0]);
+ out.attribute(null, ATTR_NAME, owner.getValue()[1]);
+ out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
+ out.endTag(null, TAG_PROFILE_OWNER);
+ }
+ }
+ out.endDocument();
+ out.flush();
+ finishWrite(outputStream);
+ } catch (IOException ioe) {
+ Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+ }
+ }
+
+ private InputStream openRead() throws IOException {
+ if (mInputStreamForTest != null) {
+ return mInputStreamForTest;
+ }
+
+ return new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+ DEVICE_OWNER_XML)).openRead();
+ }
+
+ private OutputStream startWrite() throws IOException {
+ if (mOutputStreamForTest != null) {
+ return mOutputStreamForTest;
+ }
+
+ fileForWriting = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+ DEVICE_OWNER_XML));
+ return fileForWriting.startWrite();
+ }
+
+ private void finishWrite(OutputStream stream) {
+ if (fileForWriting != null) {
+ fileForWriting.finishWrite((FileOutputStream) stream);
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 186fbe1..5a964ad 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -26,10 +26,6 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.org.conscrypt.TrustedCertificateStore;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
@@ -49,9 +45,7 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.ProxyProperties;
@@ -75,7 +69,6 @@
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
-import android.util.AtomicFile;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -84,6 +77,10 @@
import android.util.Xml;
import android.view.IWindowManager;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -132,6 +129,7 @@
IWindowManager mIWindowManager;
NotificationManager mNotificationManager;
+ // Stores and loads state on device and profile owners.
private DeviceOwner mDeviceOwner;
/**
@@ -601,6 +599,11 @@
Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
+ if (mDeviceOwner != null) {
+ mDeviceOwner.removeProfileOwner(userHandle);
+ mDeviceOwner.writeOwnerFile();
+ }
+
DevicePolicyData policy = mUserData.get(userHandle);
if (policy != null) {
mUserData.remove(userHandle);
@@ -614,9 +617,7 @@
void loadDeviceOwner() {
synchronized (this) {
- if (DeviceOwner.isRegistered()) {
- mDeviceOwner = new DeviceOwner();
- }
+ mDeviceOwner = DeviceOwner.load();
}
}
@@ -1294,7 +1295,8 @@
if (admin.getUid() != Binder.getCallingUid()) {
// If trying to remove device owner, refuse when the caller is not the owner.
if (mDeviceOwner != null
- && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
+ && adminReceiver.getPackageName().equals(
+ mDeviceOwner.getDeviceOwnerPackageName())) {
return;
}
mContext.enforceCallingOrSelfPermission(
@@ -2739,14 +2741,26 @@
+ " for device owner");
}
synchronized (this) {
- if (mDeviceOwner == null && !isDeviceProvisioned()) {
- mDeviceOwner = new DeviceOwner(packageName, ownerName);
+ if (isDeviceProvisioned()) {
+ throw new IllegalStateException(
+ "Trying to set device owner but device is already provisioned.");
+ }
+
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
+ throw new IllegalStateException(
+ "Trying to set device owner but device owner is already set.");
+ }
+
+ if (mDeviceOwner == null) {
+ // Device owner is not set and does not exist, set it.
+ mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
mDeviceOwner.writeOwnerFile();
return true;
} else {
- throw new IllegalStateException("Trying to set device owner to " + packageName
- + ", owner=" + mDeviceOwner.getPackageName()
- + ", device_provisioned=" + isDeviceProvisioned());
+ // Device owner is not set but a profile owner exists, update Device owner state.
+ mDeviceOwner.setDeviceOwner(packageName, ownerName);
+ mDeviceOwner.writeOwnerFile();
+ return true;
}
}
}
@@ -2758,7 +2772,7 @@
}
synchronized (this) {
return mDeviceOwner != null
- && mDeviceOwner.getPackageName().equals(packageName);
+ && mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
}
}
@@ -2769,7 +2783,7 @@
}
synchronized (this) {
if (mDeviceOwner != null) {
- return mDeviceOwner.getPackageName();
+ return mDeviceOwner.getDeviceOwnerPackageName();
}
}
return null;
@@ -2783,7 +2797,67 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
synchronized (this) {
if (mDeviceOwner != null) {
- return mDeviceOwner.getName();
+ return mDeviceOwner.getDeviceOwnerName();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean setProfileOwner(String packageName, String ownerName, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+ if (packageName == null
+ || !DeviceOwner.isInstalledForUser(packageName, userHandle)) {
+ throw new IllegalArgumentException("Package name " + packageName
+ + " not installed for userId:" + userHandle);
+ }
+ synchronized (this) {
+ if (isUserSetupComplete(userHandle)) {
+ throw new IllegalStateException(
+ "Trying to set profile owner but user is already set-up.");
+ }
+ if (mDeviceOwner == null) {
+ // Device owner state does not exist, create it.
+ mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
+ userHandle);
+ mDeviceOwner.writeOwnerFile();
+ return true;
+ } else {
+ // Device owner already exists, update it.
+ mDeviceOwner.setProfileOwner(packageName, ownerName, userHandle);
+ mDeviceOwner.writeOwnerFile();
+ return true;
+ }
+ }
+ }
+
+ @Override
+ public String getProfileOwner(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+
+ synchronized (this) {
+ if (mDeviceOwner != null) {
+ return mDeviceOwner.getProfileOwnerPackageName(userHandle);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getProfileOwnerName(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+ synchronized (this) {
+ if (mDeviceOwner != null) {
+ return mDeviceOwner.getProfileOwnerName(userHandle);
}
}
return null;
@@ -2794,6 +2868,11 @@
Settings.Global.DEVICE_PROVISIONED, 0) > 0;
}
+ private boolean isUserSetupComplete(int userId) {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, userId) > 0;
+ }
+
private void enforceCrossUserPermission(int userHandle) {
if (userHandle < 0) {
throw new IllegalArgumentException("Invalid userId " + userHandle);
@@ -2858,103 +2937,4 @@
}
}
}
-
- static class DeviceOwner {
- private static final String DEVICE_OWNER_XML = "device_owner.xml";
- private static final String TAG_DEVICE_OWNER = "device-owner";
- private static final String ATTR_NAME = "name";
- private static final String ATTR_PACKAGE = "package";
- private String mPackageName;
- private String mOwnerName;
-
- DeviceOwner() {
- readOwnerFile();
- }
-
- DeviceOwner(String packageName, String ownerName) {
- this.mPackageName = packageName;
- this.mOwnerName = ownerName;
- }
-
- static boolean isRegistered() {
- return new File(Environment.getSystemSecureDirectory(),
- DEVICE_OWNER_XML).exists();
- }
-
- String getPackageName() {
- return mPackageName;
- }
-
- String getName() {
- return mOwnerName;
- }
-
- static boolean isInstalled(String packageName, PackageManager pm) {
- try {
- PackageInfo pi;
- if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
- if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- return true;
- }
- }
- } catch (NameNotFoundException nnfe) {
- Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed.");
- }
- return false;
- }
-
- void readOwnerFile() {
- AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
- DEVICE_OWNER_XML));
- try {
- FileInputStream input = file.openRead();
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(input, null);
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
- }
- String tag = parser.getName();
- if (!TAG_DEVICE_OWNER.equals(tag)) {
- throw new XmlPullParserException(
- "Device Owner file does not start with device-owner tag: found " + tag);
- }
- mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
- mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
- input.close();
- } catch (XmlPullParserException xppe) {
- Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe);
- } catch (IOException ioe) {
- Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe);
- }
- }
-
- void writeOwnerFile() {
- synchronized (this) {
- writeOwnerFileLocked();
- }
- }
-
- private void writeOwnerFileLocked() {
- AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
- DEVICE_OWNER_XML));
- try {
- FileOutputStream output = file.startWrite();
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(output, "utf-8");
- out.startDocument(null, true);
- out.startTag(null, TAG_DEVICE_OWNER);
- out.attribute(null, ATTR_PACKAGE, mPackageName);
- if (mOwnerName != null) {
- out.attribute(null, ATTR_NAME, mOwnerName);
- }
- out.endTag(null, TAG_DEVICE_OWNER);
- out.endDocument();
- out.flush();
- file.finishWrite(output);
- } catch (IOException ioe) {
- Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe);
- }
- }
- }
}
diff --git a/services/devicepolicy/java/service.mk b/services/devicepolicy/java/service.mk
deleted file mode 100644
index e64cc96..0000000
--- a/services/devicepolicy/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring devicepolicy,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := devicepolicy/java
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.devicepolicy.DevicePolicyManagerService
-
-endif
diff --git a/services/core/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
similarity index 97%
rename from services/core/java/com/android/server/SystemServer.java
rename to services/java/com/android/server/SystemServer.java
index 1f6235f..9bc2201 100644
--- a/services/core/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -51,7 +51,6 @@
import com.android.internal.R;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
-import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accounts.AccountManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.BatteryStatsService;
@@ -478,8 +477,8 @@
try {
Slog.i(TAG, "Accessibility Manager");
- ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
- new AccessibilityManagerService(context));
+ ServiceManager.addService(Context.ACCESSIBILITY_SERVICE, (IBinder)
+ getClass().getClassLoader().loadClass("com.android.server.accessibility.AccessibilityManagerService").getConstructor(Context.class).newInstance(context));
} catch (Throwable e) {
reportWtf("starting Accessibility Manager", e);
}
@@ -532,8 +531,10 @@
}
try {
- Slog.i(TAG, "Device Policy");
- mSystemServiceManager.startServiceIfExists(DEVICE_POLICY_MANAGER_SERVICE_CLASS);
+ if (pm.hasSystemFeature("android.software.device_admin")) {
+ mSystemServiceManager.startServiceIfExists(
+ DEVICE_POLICY_MANAGER_SERVICE_CLASS);
+ }
} catch (Throwable e) {
reportWtf("starting DevicePolicyService", e);
}
@@ -780,15 +781,17 @@
if (!disableNonCoreServices) {
try {
- Slog.i(TAG, "Backup Service");
- mSystemServiceManager.startServiceIfExists(BACKUP_MANAGER_SERVICE_CLASS);
+ if (pm.hasSystemFeature("android.software.backup")) {
+ mSystemServiceManager.startServiceIfExists(BACKUP_MANAGER_SERVICE_CLASS);
+ }
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Backup Service", e);
}
try {
- Slog.i(TAG, "AppWidget Service");
- mSystemServiceManager.startServiceIfExists(APPWIDGET_SERVICE_CLASS);
+ if (pm.hasSystemFeature("android.software.app_widgets")) {
+ mSystemServiceManager.startServiceIfExists(APPWIDGET_SERVICE_CLASS);
+ }
} catch (Throwable e) {
reportWtf("starting AppWidget Service", e);
}
@@ -848,7 +851,7 @@
}
}
- if (!disableNonCoreServices &&
+ if (!disableNonCoreServices &&
context.getResources().getBoolean(R.bool.config_dreamsSupported)) {
try {
Slog.i(TAG, "Dreams Service");
@@ -878,8 +881,9 @@
}
try {
- Slog.i(TAG, "Print Service");
- mSystemServiceManager.startServiceIfExists(PRINT_MANAGER_SERVICE_CLASS);
+ if (pm.hasSystemFeature("android.software.print")) {
+ mSystemServiceManager.startServiceIfExists(PRINT_MANAGER_SERVICE_CLASS);
+ }
} catch (Throwable e) {
reportWtf("starting Print Service", e);
}
diff --git a/services/print/Android.mk b/services/print/Android.mk
new file mode 100644
index 0000000..33604b7
--- /dev/null
+++ b/services/print/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.print
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 7f146a7..7438297 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -52,7 +52,6 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.server.SystemService;
-import com.android.server.devicepolicy.DevicePolicyManagerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/print/java/service.mk b/services/print/java/service.mk
deleted file mode 100644
index cba3612..0000000
--- a/services/print/java/service.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Include only if the service is required
-ifneq ($(findstring print,$(REQUIRED_SERVICES)),)
-
-SUB_DIR := print/java
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,$(SUB_DIR))
-
-#DEFINED_SERVICES += com.android.server.print.PrintManagerService
-
-endif
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
new file mode 100644
index 0000000..f913b97
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.devicepolicy;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Tests for the DeviceOwner object that saves & loads device and policy owner information.
+ * run this test with:
+ * make -j FrameworksServicesTests
+ * runtest --path frameworks/base/services/tests/servicestests/ \
+ * src/com/android/server/devicepolicy/DeviceOwnerTest.java
+ */
+public class DeviceOwnerTest extends AndroidTestCase {
+
+ private ByteArrayInputStream mInputStreamForTest;
+ private ByteArrayOutputStream mOutputStreamForTest = new ByteArrayOutputStream();
+
+ @SmallTest
+ public void testDeviceOwnerOnly() throws Exception {
+ DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+ out.setDeviceOwner("some.device.owner.package", "owner");
+ out.writeOwnerFile();
+
+ mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+ DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+ in.readOwnerFile();
+
+ assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
+ assertEquals("owner", in.getDeviceOwnerName());
+ assertNull(in.getProfileOwnerPackageName(1));
+ }
+
+ @SmallTest
+ public void testProfileOwnerOnly() throws Exception {
+ DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+ out.setProfileOwner("some.profile.owner.package", "some-company", 1);
+ out.writeOwnerFile();
+
+ mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+ DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+ in.readOwnerFile();
+
+ assertNull(in.getDeviceOwnerPackageName());
+ assertNull(in.getDeviceOwnerName());
+ assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+ assertEquals("some-company", in.getProfileOwnerName(1));
+ }
+
+ @SmallTest
+ public void testDeviceAndProfileOwners() throws Exception {
+ DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+ out.setDeviceOwner("some.device.owner.package", "owner");
+ out.setProfileOwner("some.profile.owner.package", "some-company", 1);
+ out.setProfileOwner("some.other.profile.owner", "some-other-company", 2);
+ out.writeOwnerFile();
+
+ mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
+
+ DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
+ in.readOwnerFile();
+
+ assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
+ assertEquals("owner", in.getDeviceOwnerName());
+ assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+ assertEquals("some-company", in.getProfileOwnerName(1));
+ assertEquals("some.other.profile.owner", in.getProfileOwnerPackageName(2));
+ assertEquals("some-other-company", in.getProfileOwnerName(2));
+ }
+}
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/projection.xml b/tests/HwAccelerationTest/res/layout/projection.xml
index 564201a..b6e4c5e 100644
--- a/tests/HwAccelerationTest/res/layout/projection.xml
+++ b/tests/HwAccelerationTest/res/layout/projection.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<view class="com.android.test.hwui.ProjectionActivity$ProjecteeLayout"
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
+ android:background="#66ff0000"
tools:context="com.example.projection.ProjectionActivity"
tools:ignore="MergeRootFrame">
<TextView
@@ -33,4 +34,4 @@
android:layout_height="100dp"
android:textSize="50sp"
android:text="TextView"/>
-</view>
\ No newline at end of file
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
index f27652d..208c387 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
@@ -72,33 +72,6 @@
}
}
- public static class ProjecteeLayout extends LinearLayout {
- private final Paint mPaint = new Paint();
- private final RectF mRectF = new RectF();
-
- public ProjecteeLayout(Context context) {
- this(context, null);
- }
-
- public ProjecteeLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ProjecteeLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- canvas.save(0x20); // secret save flag
- mRectF.set(0, 0, getWidth(), getHeight());
- mPaint.setColor(0x5f000000);
- canvas.drawOval(mRectF, mPaint);
- canvas.restore();
- super.dispatchDraw(canvas);
- }
- }
-
static View container;
@Override
diff --git a/tests/SystemUIDemoModeController/Android.mk b/tests/SystemUIDemoModeController/Android.mk
new file mode 100644
index 0000000..64ea63c
--- /dev/null
+++ b/tests/SystemUIDemoModeController/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DemoModeController
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SystemUIDemoModeController/AndroidManifest.xml b/tests/SystemUIDemoModeController/AndroidManifest.xml
new file mode 100644
index 0000000..2e97932
--- /dev/null
+++ b/tests/SystemUIDemoModeController/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.demomodecontroller"
+ android:versionCode="1"
+ android:versionName="0.1" >
+
+ <uses-sdk
+ android:minSdkVersion="19"
+ android:targetSdkVersion="19" />
+
+ <application
+ android:allowBackup="false"
+ android:label="@string/app_name" >
+ <activity
+ android:name=".DemoModeController" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/tests/SystemUIDemoModeController/res/values/strings.xml b/tests/SystemUIDemoModeController/res/values/strings.xml
new file mode 100644
index 0000000..257a353
--- /dev/null
+++ b/tests/SystemUIDemoModeController/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?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>
+
+ <string name="app_name">Demo Mode Controller</string>
+ <string name="help_text">"Drag: control icon states\nLong-press + drag: control background color\nDouble-tap: toggle bar mode</string>
+
+</resources>
diff --git a/tests/SystemUIDemoModeController/src/com/example/android/demomodecontroller/DemoModeController.java b/tests/SystemUIDemoModeController/src/com/example/android/demomodecontroller/DemoModeController.java
new file mode 100644
index 0000000..b177d7e
--- /dev/null
+++ b/tests/SystemUIDemoModeController/src/com/example/android/demomodecontroller/DemoModeController.java
@@ -0,0 +1,340 @@
+/*
+ * 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.example.android.demomodecontroller;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+public class DemoModeController extends Activity implements OnTouchListener {
+ private static final String TAG = DemoModeController.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private final Context mContext = this;
+ private final Handler mHandler = new Handler();
+ private final PointF mLastDown = new PointF();
+
+ private View mContent;
+ private Handler mBackground;
+ private int mTouchSlop;
+ private long mLastDownTime;
+ private boolean mControllingColor;
+ private Toast mToast;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS // so WM gives us enough room
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+ getActionBar().hide();
+ mContent = new View(mContext);
+ mContent.setBackgroundColor(0xff33b5e5);
+ mContent.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ mContent.setOnTouchListener(this);
+ setContentView(mContent);
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+
+ final HandlerThread background = new HandlerThread("background");
+ background.start();
+ mBackground = new Handler(background.getLooper());
+ updateMode();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ exitDemoMode();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ exitDemoMode();
+ mToast = Toast.makeText(mContext, R.string.help_text, Toast.LENGTH_LONG);
+ mToast.show();
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (mToast != null) {
+ mToast.cancel();
+ mToast = null;
+ }
+ final int action = event.getAction();
+ if (action == MotionEvent.ACTION_DOWN) {
+ if (DEBUG) Log.d(TAG, "down");
+ mHandler.postDelayed(mLongPressCheck, 500);
+ final long now = SystemClock.uptimeMillis();
+ if (now - mLastDownTime < 200) {
+ toggleMode();
+ }
+ mLastDownTime = now;
+ mLastDown.x = event.getX();
+ mLastDown.y = event.getY();
+ return true;
+ }
+ if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+ if (DEBUG) Log.d(TAG, "upOrCancel");
+ mControllingColor = false;
+ mHandler.removeCallbacks(mLongPressCheck);
+ }
+ if (action != MotionEvent.ACTION_MOVE) return false;
+
+ float x = event.getX();
+ float y = event.getY();
+ if (Math.abs(mLastDown.x - x) > mTouchSlop || Math.abs(mLastDown.y - y) > mTouchSlop) {
+ mHandler.removeCallbacks(mLongPressCheck);
+ }
+ x = Math.max(x, 0);
+ y = Math.max(y, 0);
+ final int h = mContent.getMeasuredHeight();
+ final int w = mContent.getMeasuredWidth();
+ x = Math.min(x, w);
+ y = Math.min(y, h);
+
+ y = h - y;
+ x = w - x;
+
+ if (mControllingColor) {
+ final float hue = y / (h / 360);
+ final float sat = 1 - (x / (float)w);
+ final float val = x / (float)w;
+ final int color = Color.HSVToColor(new float[]{hue, sat, val});
+ if (DEBUG) Log.d(TAG, String.format("hsv=(%s,%s,%s) argb=#%08x", hue, sat, val, color));
+ mContent.setBackgroundColor(color);
+ return true;
+ }
+
+ final int hh = (int)x / (w / 12);
+ if (hh != mHH) {
+ mHH = hh;
+ mBackground.removeCallbacks(mUpdateClock);
+ mBackground.post(mUpdateClock);
+ }
+
+ final int mm = (int)y / (h / 60);
+ if (mm != mMM) {
+ mMM = mm;
+ mBackground.removeCallbacks(mUpdateClock);
+ mBackground.post(mUpdateClock);
+ }
+
+ final int batteryLevel = (int)y / (h / 101);
+ if (batteryLevel != mBatteryLevel) {
+ mBatteryLevel = batteryLevel;
+ mBackground.removeCallbacks(mUpdateBattery);
+ mBackground.post(mUpdateBattery);
+ }
+
+ final boolean batteryPlugged = x >= w / 2;
+ if (batteryPlugged != mBatteryPlugged) {
+ mBatteryPlugged = batteryPlugged;
+ mBackground.removeCallbacks(mUpdateBattery);
+ mBackground.post(mUpdateBattery);
+ }
+
+ final int mobileLevel = (int)y / (h / 10);
+ if (mobileLevel != mMobileLevel) {
+ mMobileLevel = mobileLevel;
+ mBackground.removeCallbacks(mUpdateMobile);
+ mBackground.post(mUpdateMobile);
+ }
+
+ final int wifiLevel = (int)y / (h / 10);
+ if (wifiLevel != mWifiLevel) {
+ mWifiLevel = wifiLevel;
+ mBackground.removeCallbacks(mUpdateWifi);
+ mBackground.post(mUpdateWifi);
+ }
+
+ final int statusSlots = (int)x / (w / 13);
+ if (statusSlots != mStatusSlots) {
+ mStatusSlots = statusSlots;
+ mBackground.removeCallbacks(mUpdateStatus);
+ mBackground.post(mUpdateStatus);
+ }
+
+ final int networkIcons = (int)x / (w / 4);
+ if (networkIcons != mNetworkIcons) {
+ mNetworkIcons = networkIcons;
+ mBackground.removeCallbacks(mUpdateNetwork);
+ mBackground.post(mUpdateNetwork);
+ }
+
+ final int mobileDataType = (int)y / (h / 9);
+ if (mobileDataType != mMobileDataType) {
+ mMobileDataType = mobileDataType;
+ mBackground.removeCallbacks(mUpdateMobile);
+ mBackground.post(mUpdateMobile);
+ }
+ return true;
+ }
+
+ private void toggleMode() {
+ if (DEBUG) Log.d(TAG, "toggleMode");
+ mBarMode = (mBarMode + 1) % 3;
+ updateMode();
+ }
+
+ private void updateMode() {
+ mBackground.removeCallbacks(mUpdateBarMode);
+ mBackground.post(mUpdateBarMode);
+ }
+
+ private final Runnable mLongPressCheck = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) Log.d(TAG, "mControllingColor = true");
+ mControllingColor = true;
+
+ }
+ };
+
+ private void exitDemoMode() {
+ if (DEBUG) Log.d(TAG, "exitDemoMode");
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "exit");
+ mContext.sendBroadcast(intent);
+ }
+
+ private int mStatusSlots; // 0 - 12
+ private final Runnable mUpdateStatus = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "status");
+ intent.putExtra("volume", mStatusSlots < 1 ? "hide"
+ : mStatusSlots < 2 ? "silent" : "vibrate");
+ intent.putExtra("bluetooth", mStatusSlots < 3 ? "hide"
+ : mStatusSlots < 4 ? "disconnected" : "connected");
+ intent.putExtra("location", mStatusSlots < 5 ? "hide" : "show");
+ intent.putExtra("alarm", mStatusSlots < 6 ? "hide" : "show");
+ intent.putExtra("sync", mStatusSlots < 7 ? "hide" : "show");
+ intent.putExtra("tty", mStatusSlots < 8 ? "hide" : "show");
+ intent.putExtra("eri", mStatusSlots < 9 ? "hide" : "show");
+ intent.putExtra("secure", mStatusSlots < 10 ? "hide" : "show");
+ intent.putExtra("mute", mStatusSlots < 11 ? "hide" : "show");
+ intent.putExtra("speakerphone", mStatusSlots < 12 ? "hide" : "show");
+ mContext.sendBroadcast(intent);
+ }
+ };
+
+ private int mNetworkIcons; // 0:airplane 1:mobile 2:airplane+wifi 3:mobile+wifi
+ private final Runnable mUpdateNetwork = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "network");
+ intent.putExtra("airplane", mNetworkIcons % 2 == 0 ? "show" : "hide");
+ intent.putExtra("wifi", mNetworkIcons >= 2 ? "show" : "hide");
+ intent.putExtra("mobile", mNetworkIcons % 2 == 1 ? "show" : "hide");
+ mContext.sendBroadcast(intent);
+ }
+ };
+
+ private int mWifiLevel; // 0 - 4, 5 - 9, fully
+ private final Runnable mUpdateWifi = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "network");
+ intent.putExtra("wifi", mNetworkIcons >= 2 ? "show" : "hide");
+ intent.putExtra("level", Integer.toString(mWifiLevel % 5));
+ intent.putExtra("fully", Boolean.toString(mWifiLevel > 4));
+ mContext.sendBroadcast(intent);
+ }
+ };
+
+ private int mMobileLevel; // 0 - 4, 5 - 9, fully
+ private int mMobileDataType; // 0 - 8
+ private static final String getDataType(int dataType) {
+ if (dataType == 1) return "1x";
+ if (dataType == 2) return "3g";
+ if (dataType == 3) return "4g";
+ if (dataType == 4) return "e";
+ if (dataType == 5) return "g";
+ if (dataType == 6) return "h";
+ if (dataType == 7) return "lte";
+ if (dataType == 8) return "roam";
+ return "";
+ }
+ private final Runnable mUpdateMobile = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "network");
+ intent.putExtra("mobile", mNetworkIcons % 2 == 1 ? "show" : "hide");
+ intent.putExtra("level", Integer.toString(mMobileLevel % 5));
+ intent.putExtra("fully", Boolean.toString(mMobileLevel > 4));
+ intent.putExtra("datatype", getDataType(mMobileDataType));
+ mContext.sendBroadcast(intent);
+ }
+ };
+
+ private boolean mBatteryPlugged;
+ private int mBatteryLevel; // 0 - 100
+ private final Runnable mUpdateBattery = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "battery");
+ intent.putExtra("level", Integer.toString(mBatteryLevel));
+ intent.putExtra("plugged", Boolean.toString(mBatteryPlugged));
+ mContext.sendBroadcast(intent);
+ }
+ };
+
+ private int mHH; // 0 - 11
+ private int mMM; // 0 - 59
+ private final Runnable mUpdateClock = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "clock");
+ intent.putExtra("hhmm", String.format("%02d%02d", mHH + 1, mMM));
+ mContext.sendBroadcast(intent);
+ }
+ };
+
+ private int mBarMode; // 0 - 2 (opaque, semi-transparent, translucent)
+ private final Runnable mUpdateBarMode = new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent("com.android.systemui.demo");
+ intent.putExtra("command", "bars");
+ intent.putExtra("mode", mBarMode == 1 ? "semi-transparent"
+ : mBarMode == 2 ? "translucent" : "opaque");
+ mContext.sendBroadcast(intent);
+ }
+ };
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 6a3c506..f9a2d19 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -149,205 +149,506 @@
// =========================================================================
// =========================================================================
-status_t
-AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
+/* static */ void AaptLocaleValue::splitAndLowerCase(const char* const chars,
+ Vector<String8>* parts, const char separator) {
+ const char *p = chars;
+ const char *q;
+ while (NULL != (q = strchr(p, separator))) {
+ String8 val(p, q - p);
+ val.toLower();
+ parts->add(val);
+ p = q+1;
+ }
+
+ if (p < chars + strlen(chars)) {
+ String8 val(p);
+ val.toLower();
+ parts->add(val);
+ }
+}
+
+/* static */
+inline bool isAlpha(const String8& string) {
+ const size_t length = string.length();
+ for (size_t i = 0; i < length; ++i) {
+ if (!isalpha(string[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* static */
+inline bool isNumber(const String8& string) {
+ const size_t length = string.length();
+ for (size_t i = 0; i < length; ++i) {
+ if (!isdigit(string[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void AaptLocaleValue::setLanguage(const char* languageChars) {
+ size_t i = 0;
+ while ((*languageChars) != '\0') {
+ language[i++] = tolower(*languageChars);
+ languageChars++;
+ }
+}
+
+void AaptLocaleValue::setRegion(const char* regionChars) {
+ size_t i = 0;
+ while ((*regionChars) != '\0') {
+ region[i++] = toupper(*regionChars);
+ regionChars++;
+ }
+}
+
+void AaptLocaleValue::setScript(const char* scriptChars) {
+ size_t i = 0;
+ while ((*scriptChars) != '\0') {
+ if (i == 0) {
+ script[i++] = toupper(*scriptChars);
+ } else {
+ script[i++] = tolower(*scriptChars);
+ }
+ scriptChars++;
+ }
+}
+
+void AaptLocaleValue::setVariant(const char* variantChars) {
+ size_t i = 0;
+ while ((*variantChars) != '\0') {
+ variant[i++] = *variantChars;
+ variantChars++;
+ }
+}
+
+bool AaptLocaleValue::initFromFilterString(const String8& str) {
+ // A locale (as specified in the filter) is an underscore separated name such
+ // as "en_US", "en_Latn_US", or "en_US_POSIX".
+ Vector<String8> parts;
+ splitAndLowerCase(str.string(), &parts, '_');
+
+ const int numTags = parts.size();
+ bool valid = false;
+ if (numTags >= 1) {
+ const String8& lang = parts[0];
+ if (isAlpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
+ setLanguage(lang.string());
+ valid = true;
+ }
+ }
+
+ if (!valid || numTags == 1) {
+ return valid;
+ }
+
+ // At this point, valid == true && numTags > 1.
+ const String8& part2 = parts[1];
+ if ((part2.length() == 2 && isAlpha(part2)) ||
+ (part2.length() == 3 && isNumber(part2))) {
+ setRegion(part2.string());
+ } else if (part2.length() == 4 && isAlpha(part2)) {
+ setScript(part2.string());
+ } else if (part2.length() >= 5 && part2.length() <= 8) {
+ setVariant(part2.string());
+ } else {
+ valid = false;
+ }
+
+ if (!valid || numTags == 2) {
+ return valid;
+ }
+
+ // At this point, valid == true && numTags > 1.
+ const String8& part3 = parts[2];
+ if (((part3.length() == 2 && isAlpha(part3)) ||
+ (part3.length() == 3 && isNumber(part3))) && script[0]) {
+ setRegion(part3.string());
+ } else if (part3.length() >= 5 && part3.length() <= 8) {
+ setVariant(part3.string());
+ } else {
+ valid = false;
+ }
+
+ if (!valid || numTags == 3) {
+ return valid;
+ }
+
+ const String8& part4 = parts[3];
+ if (part4.length() >= 5 && part4.length() <= 8) {
+ setVariant(part4.string());
+ } else {
+ valid = false;
+ }
+
+ if (!valid || numTags > 4) {
+ return false;
+ }
+
+ return true;
+}
+
+int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int startIndex) {
+ const int size = parts.size();
+ int currentIndex = startIndex;
+
+ String8 part = parts[currentIndex];
+ if (part[0] == 'b' && part[1] == '+') {
+ // This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
+ // except that the separator is "+" and not "-".
+ Vector<String8> subtags;
+ AaptLocaleValue::splitAndLowerCase(part.string(), &subtags, '+');
+ subtags.removeItemsAt(0);
+ if (subtags.size() == 1) {
+ setLanguage(subtags[0]);
+ } else if (subtags.size() == 2) {
+ setLanguage(subtags[0]);
+
+ // The second tag can either be a region, a variant or a script.
+ switch (subtags[1].size()) {
+ case 2:
+ case 3:
+ setRegion(subtags[1]);
+ break;
+ case 4:
+ setScript(subtags[1]);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ setVariant(subtags[1]);
+ break;
+ default:
+ fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n",
+ part.string());
+ return -1;
+ }
+ } else if (subtags.size() == 3) {
+ // The language is always the first subtag.
+ setLanguage(subtags[0]);
+
+ // The second subtag can either be a script or a region code.
+ // If its size is 4, it's a script code, else it's a region code.
+ bool hasRegion = false;
+ if (subtags[1].size() == 4) {
+ setScript(subtags[1]);
+ } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
+ setRegion(subtags[1]);
+ hasRegion = true;
+ } else {
+ fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n", part.string());
+ return -1;
+ }
+
+ // The third tag can either be a region code (if the second tag was
+ // a script), else a variant code.
+ if (subtags[2].size() > 4) {
+ setVariant(subtags[2]);
+ } else {
+ setRegion(subtags[2]);
+ }
+ } else if (subtags.size() == 4) {
+ setLanguage(subtags[0]);
+ setScript(subtags[1]);
+ setRegion(subtags[2]);
+ setVariant(subtags[3]);
+ } else {
+ fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name: %s\n", part.string());
+ return -1;
+ }
+
+ return ++currentIndex;
+ } else {
+ if ((part.length() == 2 || part.length() == 3) && isAlpha(part)) {
+ setLanguage(part);
+ if (++currentIndex == size) {
+ return size;
+ }
+ } else {
+ return currentIndex;
+ }
+
+ part = parts[currentIndex];
+ if (part.string()[0] == 'r' && part.length() == 3) {
+ setRegion(part.string() + 1);
+ if (++currentIndex == size) {
+ return size;
+ }
+ }
+ }
+
+ return currentIndex;
+}
+
+
+String8 AaptLocaleValue::toDirName() const {
+ String8 dirName("");
+ if (language[0]) {
+ dirName += language;
+ } else {
+ return dirName;
+ }
+
+ if (script[0]) {
+ dirName += "-s";
+ dirName += script;
+ }
+
+ if (region[0]) {
+ dirName += "-r";
+ dirName += region;
+ }
+
+ if (variant[0]) {
+ dirName += "-v";
+ dirName += variant;
+ }
+
+ return dirName;
+}
+
+void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
+ config.unpackLanguage(language);
+ config.unpackRegion(region);
+ if (config.localeScript[0]) {
+ memcpy(script, config.localeScript, sizeof(config.localeScript));
+ }
+
+ if (config.localeVariant[0]) {
+ memcpy(variant, config.localeVariant, sizeof(config.localeVariant));
+ }
+}
+
+void AaptLocaleValue::writeTo(ResTable_config* out) const {
+ out->packLanguage(language);
+ out->packRegion(region);
+
+ if (script[0]) {
+ memcpy(out->localeScript, script, sizeof(out->localeScript));
+ }
+
+ if (variant[0]) {
+ memcpy(out->localeVariant, variant, sizeof(out->localeVariant));
+ }
+}
+
+
+/* static */ bool
+AaptGroupEntry::parseFilterNamePart(const String8& part, int* axis, AxisValue* value)
{
ResTable_config config;
+ memset(&config, 0, sizeof(ResTable_config));
// IMSI - MCC
if (getMccName(part.string(), &config)) {
*axis = AXIS_MCC;
- *value = config.mcc;
- return 0;
+ value->intValue = config.mcc;
+ return true;
}
// IMSI - MNC
if (getMncName(part.string(), &config)) {
*axis = AXIS_MNC;
- *value = config.mnc;
- return 0;
+ value->intValue = config.mnc;
+ return true;
}
// locale - language
- if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
- *axis = AXIS_LANGUAGE;
- *value = part[1] << 8 | part[0];
- return 0;
- }
-
- // locale - language_REGION
- if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1])
- && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) {
- *axis = AXIS_LANGUAGE;
- *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]);
- return 0;
+ if (value->localeValue.initFromFilterString(part)) {
+ *axis = AXIS_LOCALE;
+ return true;
}
// layout direction
if (getLayoutDirectionName(part.string(), &config)) {
*axis = AXIS_LAYOUTDIR;
- *value = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
- return 0;
+ value->intValue = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
+ return true;
}
// smallest screen dp width
if (getSmallestScreenWidthDpName(part.string(), &config)) {
*axis = AXIS_SMALLESTSCREENWIDTHDP;
- *value = config.smallestScreenWidthDp;
- return 0;
+ value->intValue = config.smallestScreenWidthDp;
+ return true;
}
// screen dp width
if (getScreenWidthDpName(part.string(), &config)) {
*axis = AXIS_SCREENWIDTHDP;
- *value = config.screenWidthDp;
- return 0;
+ value->intValue = config.screenWidthDp;
+ return true;
}
// screen dp height
if (getScreenHeightDpName(part.string(), &config)) {
*axis = AXIS_SCREENHEIGHTDP;
- *value = config.screenHeightDp;
- return 0;
+ value->intValue = config.screenHeightDp;
+ return true;
}
// screen layout size
if (getScreenLayoutSizeName(part.string(), &config)) {
*axis = AXIS_SCREENLAYOUTSIZE;
- *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
- return 0;
+ value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
+ return true;
}
// screen layout long
if (getScreenLayoutLongName(part.string(), &config)) {
*axis = AXIS_SCREENLAYOUTLONG;
- *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
- return 0;
+ value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
+ return true;
}
// orientation
if (getOrientationName(part.string(), &config)) {
*axis = AXIS_ORIENTATION;
- *value = config.orientation;
- return 0;
+ value->intValue = config.orientation;
+ return true;
}
// ui mode type
if (getUiModeTypeName(part.string(), &config)) {
*axis = AXIS_UIMODETYPE;
- *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
- return 0;
+ value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
+ return true;
}
// ui mode night
if (getUiModeNightName(part.string(), &config)) {
*axis = AXIS_UIMODENIGHT;
- *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
- return 0;
+ value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
+ return true;
}
// density
if (getDensityName(part.string(), &config)) {
*axis = AXIS_DENSITY;
- *value = config.density;
- return 0;
+ value->intValue = config.density;
+ return true;
}
// touchscreen
if (getTouchscreenName(part.string(), &config)) {
*axis = AXIS_TOUCHSCREEN;
- *value = config.touchscreen;
- return 0;
+ value->intValue = config.touchscreen;
+ return true;
}
// keyboard hidden
if (getKeysHiddenName(part.string(), &config)) {
*axis = AXIS_KEYSHIDDEN;
- *value = config.inputFlags;
- return 0;
+ value->intValue = config.inputFlags;
+ return true;
}
// keyboard
if (getKeyboardName(part.string(), &config)) {
*axis = AXIS_KEYBOARD;
- *value = config.keyboard;
- return 0;
+ value->intValue = config.keyboard;
+ return true;
}
// navigation hidden
if (getNavHiddenName(part.string(), &config)) {
*axis = AXIS_NAVHIDDEN;
- *value = config.inputFlags;
+ value->intValue = config.inputFlags;
return 0;
}
// navigation
if (getNavigationName(part.string(), &config)) {
*axis = AXIS_NAVIGATION;
- *value = config.navigation;
- return 0;
+ value->intValue = config.navigation;
+ return true;
}
// screen size
if (getScreenSizeName(part.string(), &config)) {
*axis = AXIS_SCREENSIZE;
- *value = config.screenSize;
- return 0;
+ value->intValue = config.screenSize;
+ return true;
}
// version
if (getVersionName(part.string(), &config)) {
*axis = AXIS_VERSION;
- *value = config.version;
- return 0;
+ value->intValue = config.version;
+ return true;
}
- return 1;
+ return false;
}
-uint32_t
+AxisValue
AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
{
+ AxisValue value;
switch (axis) {
case AXIS_MCC:
- return config.mcc;
+ value.intValue = config.mcc;
+ break;
case AXIS_MNC:
- return config.mnc;
- case AXIS_LANGUAGE:
- return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16)
- | (((uint32_t)config.language[1]) << 8) | (config.language[0]);
+ value.intValue = config.mnc;
+ break;
+ case AXIS_LOCALE:
+ value.localeValue.initFromResTable(config);
+ break;
case AXIS_LAYOUTDIR:
- return config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
+ value.intValue = config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
+ break;
case AXIS_SCREENLAYOUTSIZE:
- return config.screenLayout&ResTable_config::MASK_SCREENSIZE;
+ value.intValue = config.screenLayout&ResTable_config::MASK_SCREENSIZE;
+ break;
case AXIS_ORIENTATION:
- return config.orientation;
+ value.intValue = config.orientation;
+ break;
case AXIS_UIMODETYPE:
- return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
+ value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
+ break;
case AXIS_UIMODENIGHT:
- return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
+ value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
+ break;
case AXIS_DENSITY:
- return config.density;
+ value.intValue = config.density;
+ break;
case AXIS_TOUCHSCREEN:
- return config.touchscreen;
+ value.intValue = config.touchscreen;
+ break;
case AXIS_KEYSHIDDEN:
- return config.inputFlags;
+ value.intValue = config.inputFlags;
+ break;
case AXIS_KEYBOARD:
- return config.keyboard;
+ value.intValue = config.keyboard;
+ break;
case AXIS_NAVIGATION:
- return config.navigation;
+ value.intValue = config.navigation;
+ break;
case AXIS_SCREENSIZE:
- return config.screenSize;
+ value.intValue = config.screenSize;
+ break;
case AXIS_SMALLESTSCREENWIDTHDP:
- return config.smallestScreenWidthDp;
+ value.intValue = config.smallestScreenWidthDp;
+ break;
case AXIS_SCREENWIDTHDP:
- return config.screenWidthDp;
+ value.intValue = config.screenWidthDp;
+ break;
case AXIS_SCREENHEIGHTDP:
- return config.screenHeightDp;
+ value.intValue = config.screenHeightDp;
+ break;
case AXIS_VERSION:
- return config.version;
+ value.intValue = config.version;
+ break;
}
- return 0;
+
+ return value;
}
bool
@@ -371,24 +672,14 @@
mParamsChanged = true;
Vector<String8> parts;
+ AaptLocaleValue::splitAndLowerCase(dir, &parts, '-');
- String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
+ String8 mcc, mnc, layoutsize, layoutlong, orient, den;
String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
- const char *p = dir;
- const char *q;
- while (NULL != (q = strchr(p, '-'))) {
- String8 val(p, q-p);
- val.toLower();
- parts.add(val);
- //printf("part: %s\n", parts[parts.size()-1].string());
- p = q+1;
- }
- String8 val(p);
- val.toLower();
- parts.add(val);
- //printf("part: %s\n", parts[parts.size()-1].string());
+ AaptLocaleValue locale;
+ int numLocaleComponents = 0;
const int N = parts.size();
int index = 0;
@@ -429,38 +720,18 @@
}
part = parts[index];
} else {
- //printf("not mcc: %s\n", part.string());
+ //printf("not mnc: %s\n", part.string());
}
- // locale - language
- if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
- loc = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not language: %s\n", part.string());
+ index = locale.initFromDirName(parts, index);
+ if (index == -1) {
+ return false;
+ }
+ if (index >= N){
+ goto success;
}
- // locale - region
- if (loc.length() > 0
- && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) {
- loc += "-";
- part.toUpper();
- loc += part.string() + 1;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not region: %s\n", part.string());
- }
-
+ part = parts[index];
if (getLayoutDirectionName(part.string())) {
layoutDir = part;
@@ -679,7 +950,7 @@
success:
this->mcc = mcc;
this->mnc = mnc;
- this->locale = loc;
+ this->locale = locale;
this->screenLayoutSize = layoutsize;
this->screenLayoutLong = layoutlong;
this->smallestScreenWidthDp = smallestwidthdp;
@@ -711,7 +982,7 @@
s += ",";
s += this->mnc;
s += ",";
- s += this->locale;
+ s += locale.toDirName();
s += ",";
s += layoutDirection;
s += ",";
@@ -765,12 +1036,15 @@
}
s += mnc;
}
- if (this->locale != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += locale;
+
+ const String8 localeComponent = locale.toDirName();
+ if (localeComponent != "") {
+ if (s.length() > 0) {
+ s += "-";
+ }
+ s += localeComponent;
}
+
if (this->layoutDirection != "") {
if (s.length() > 0) {
s += "-";
@@ -942,55 +1216,6 @@
return true;
}
-/*
- * Does this directory name fit the pattern of a locale dir ("en-rUS" or
- * "default")?
- *
- * TODO: Should insist that the first two letters are lower case, and the
- * second two are upper.
- */
-bool AaptGroupEntry::getLocaleName(const char* fileName,
- ResTable_config* out)
-{
- if (strcmp(fileName, kWildcardName) == 0
- || strcmp(fileName, kDefaultLocale) == 0) {
- if (out) {
- out->language[0] = 0;
- out->language[1] = 0;
- out->country[0] = 0;
- out->country[1] = 0;
- }
- return true;
- }
-
- if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
- if (out) {
- out->language[0] = fileName[0];
- out->language[1] = fileName[1];
- out->country[0] = 0;
- out->country[1] = 0;
- }
- return true;
- }
-
- if (strlen(fileName) == 5 &&
- isalpha(fileName[0]) &&
- isalpha(fileName[1]) &&
- fileName[2] == '-' &&
- isalpha(fileName[3]) &&
- isalpha(fileName[4])) {
- if (out) {
- out->language[0] = fileName[0];
- out->language[1] = fileName[1];
- out->country[0] = fileName[3];
- out->country[1] = fileName[4];
- }
- return true;
- }
-
- return false;
-}
-
bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
{
if (strcmp(name, kWildcardName) == 0) {
@@ -1496,18 +1721,18 @@
return v;
}
-const ResTable_config& AaptGroupEntry::toParams() const
+const ResTable_config AaptGroupEntry::toParams() const
{
if (!mParamsChanged) {
return mParams;
}
mParamsChanged = false;
- ResTable_config& params(mParams);
- memset(¶ms, 0, sizeof(params));
+ ResTable_config& params = mParams;
+ memset(¶ms, 0, sizeof(ResTable_config));
getMccName(mcc.string(), ¶ms);
getMncName(mnc.string(), ¶ms);
- getLocaleName(locale.string(), ¶ms);
+ locale.writeTo(¶ms);
getLayoutDirectionName(layoutDirection.string(), ¶ms);
getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), ¶ms);
getScreenWidthDpName(screenWidthDp.string(), ¶ms);
@@ -1992,7 +2217,9 @@
AaptAssets::AaptAssets()
: AaptDir(String8(), String8()),
- mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
+ mHavePrivateSymbols(false),
+ mChanged(false), mHaveIncludedAssets(false),
+ mRes(NULL)
{
}
@@ -2505,9 +2732,9 @@
// If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
// pick xhdpi.
uint32_t preferredDensity = 0;
- const SortedVector<uint32_t>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
+ const SortedVector<AxisValue>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
if (preferredConfigs != NULL && preferredConfigs->size() > 0) {
- preferredDensity = (*preferredConfigs)[0];
+ preferredDensity = (*preferredConfigs)[0].intValue;
}
// Now deal with preferred configurations.
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 9cc9007..336d08b 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -13,7 +13,6 @@
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
-#include <utils/String8.h>
#include <utils/Vector.h>
#include "ZipFile.h"
@@ -34,8 +33,7 @@
AXIS_NONE = 0,
AXIS_MCC = 1,
AXIS_MNC,
- AXIS_LANGUAGE,
- AXIS_REGION,
+ AXIS_LOCALE,
AXIS_SCREENLAYOUTSIZE,
AXIS_SCREENLAYOUTLONG,
AXIS_ORIENTATION,
@@ -58,6 +56,73 @@
AXIS_END = AXIS_VERSION,
};
+struct AaptLocaleValue {
+ char language[4];
+ char region[4];
+ char script[4];
+ char variant[8];
+
+ AaptLocaleValue() {
+ memset(this, 0, sizeof(AaptLocaleValue));
+ }
+
+ // Initialize this AaptLocaleValue from a config string.
+ bool initFromFilterString(const String8& config);
+
+ int initFromDirName(const Vector<String8>& parts, const int startIndex);
+
+ // Initialize this AaptLocaleValue from a ResTable_config.
+ void initFromResTable(const ResTable_config& config);
+
+ void writeTo(ResTable_config* out) const;
+
+ String8 toDirName() const;
+
+ int compare(const AaptLocaleValue& other) const {
+ return memcmp(this, &other, sizeof(AaptLocaleValue));
+ }
+
+ static void splitAndLowerCase(const char* const chars, Vector<String8>* parts,
+ const char separator);
+
+ inline bool operator<(const AaptLocaleValue& o) const { return compare(o) < 0; }
+ inline bool operator<=(const AaptLocaleValue& o) const { return compare(o) <= 0; }
+ inline bool operator==(const AaptLocaleValue& o) const { return compare(o) == 0; }
+ inline bool operator!=(const AaptLocaleValue& o) const { return compare(o) != 0; }
+ inline bool operator>=(const AaptLocaleValue& o) const { return compare(o) >= 0; }
+ inline bool operator>(const AaptLocaleValue& o) const { return compare(o) > 0; }
+private:
+ void setLanguage(const char* language);
+ void setRegion(const char* language);
+ void setScript(const char* script);
+ void setVariant(const char* variant);
+};
+
+struct AxisValue {
+ // Used for all axes except AXIS_LOCALE, which is represented
+ // as a AaptLocaleValue value.
+ int intValue;
+ AaptLocaleValue localeValue;
+
+ AxisValue() : intValue(0) {
+ }
+
+ inline int compare(const AxisValue &other) const {
+ if (intValue != other.intValue) {
+ return intValue - other.intValue;
+ }
+
+ return localeValue.compare(other.localeValue);
+ }
+
+ inline bool operator<(const AxisValue& o) const { return compare(o) < 0; }
+ inline bool operator<=(const AxisValue& o) const { return compare(o) <= 0; }
+ inline bool operator==(const AxisValue& o) const { return compare(o) == 0; }
+ inline bool operator!=(const AxisValue& o) const { return compare(o) != 0; }
+ inline bool operator>=(const AxisValue& o) const { return compare(o) >= 0; }
+ inline bool operator>(const AxisValue& o) const { return compare(o) > 0; }
+};
+
/**
* This structure contains a specific variation of a single file out
* of all the variations it can have that we can have.
@@ -65,22 +130,38 @@
struct AaptGroupEntry
{
public:
- AaptGroupEntry() : mParamsChanged(true) { }
- AaptGroupEntry(const String8& _locale, const String8& _vendor)
- : locale(_locale), vendor(_vendor), mParamsChanged(true) { }
+ AaptGroupEntry() : mParamsChanged(true) {
+ memset(&mParams, 0, sizeof(ResTable_config));
+ }
bool initFromDirName(const char* dir, String8* resType);
- static status_t parseNamePart(const String8& part, int* axis, uint32_t* value);
+ static bool parseFilterNamePart(const String8& part, int* axis, AxisValue* value);
- static uint32_t getConfigValueForAxis(const ResTable_config& config, int axis);
+ static AxisValue getConfigValueForAxis(const ResTable_config& config, int axis);
static bool configSameExcept(const ResTable_config& config,
const ResTable_config& otherConfig, int axis);
+ int compare(const AaptGroupEntry& o) const;
+
+ const ResTable_config toParams() const;
+
+ inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
+ inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
+ inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
+ inline bool operator!=(const AaptGroupEntry& o) const { return compare(o) != 0; }
+ inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
+ inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
+
+ String8 toString() const;
+ String8 toDirName(const String8& resType) const;
+
+ const String8& getVersionString() const { return version; }
+
+private:
static bool getMccName(const char* name, ResTable_config* out = NULL);
static bool getMncName(const char* name, ResTable_config* out = NULL);
- static bool getLocaleName(const char* name, ResTable_config* out = NULL);
static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL);
static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL);
static bool getOrientationName(const char* name, ResTable_config* out = NULL);
@@ -99,26 +180,9 @@
static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL);
static bool getVersionName(const char* name, ResTable_config* out = NULL);
- int compare(const AaptGroupEntry& o) const;
-
- const ResTable_config& toParams() const;
-
- inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
- inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
- inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
- inline bool operator!=(const AaptGroupEntry& o) const { return compare(o) != 0; }
- inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
- inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
-
- String8 toString() const;
- String8 toDirName(const String8& resType) const;
-
- const String8& getVersionString() const { return version; }
-
-private:
String8 mcc;
String8 mnc;
- String8 locale;
+ AaptLocaleValue locale;
String8 vendor;
String8 smallestScreenWidthDp;
String8 screenWidthDp;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 48e3125..8e856b7 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -600,6 +600,7 @@
// the API version because key resources like icons will have an implicit
// version if they are using newer config types like density.
ResTable_config config;
+ memset(&config, 0, sizeof(ResTable_config));
config.language[0] = 'e';
config.language[1] = 'n';
config.country[0] = 'U';
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index a390e42..c923bc2 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -80,6 +80,7 @@
ResourceDirIterator(const sp<ResourceTypeSet>& set, const String8& resType)
: mResType(resType), mSet(set), mSetPos(0), mGroupPos(0)
{
+ memset(&mParams, 0, sizeof(ResTable_config));
}
inline const sp<AaptGroup>& getGroup() const { return mGroup; }
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index 8cfd2a5..e8a2be4 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -28,8 +28,8 @@
mContainsPseudo = true;
}
int axis;
- uint32_t value;
- if (AaptGroupEntry::parseNamePart(part, &axis, &value)) {
+ AxisValue value;
+ if (!AaptGroupEntry::parseFilterNamePart(part, &axis, &value)) {
fprintf(stderr, "Invalid configuration: %s\n", arg);
fprintf(stderr, " ");
for (int i=0; i<p-arg; i++) {
@@ -44,15 +44,20 @@
ssize_t index = mData.indexOfKey(axis);
if (index < 0) {
- mData.add(axis, SortedVector<uint32_t>());
+ mData.add(axis, SortedVector<AxisValue>());
}
- SortedVector<uint32_t>& sv = mData.editValueFor(axis);
+ SortedVector<AxisValue>& sv = mData.editValueFor(axis);
sv.add(value);
- // if it's a locale with a region, also match an unmodified locale of the
- // same language
- if (axis == AXIS_LANGUAGE) {
- if (value & 0xffff0000) {
- sv.add(value & 0x0000ffff);
+
+ // If it's a locale with a region, script or variant, we should also match an
+ // unmodified locale of the same language
+ if (axis == AXIS_LOCALE) {
+ if (value.localeValue.region[0] || value.localeValue.script[0] ||
+ value.localeValue.variant[0]) {
+ AxisValue copy;
+ memcpy(copy.localeValue.language, value.localeValue.language,
+ sizeof(value.localeValue.language));
+ sv.add(copy);
}
}
p = q;
@@ -70,9 +75,9 @@
}
bool
-ResourceFilter::match(int axis, uint32_t value) const
+ResourceFilter::match(int axis, const AxisValue& value) const
{
- if (value == 0) {
+ if (value.intValue == 0 && (value.localeValue.language[0] == 0)) {
// they didn't specify anything so take everything
return true;
}
@@ -81,7 +86,7 @@
// we didn't request anything on this axis so take everything
return true;
}
- const SortedVector<uint32_t>& sv = mData.valueAt(index);
+ const SortedVector<AxisValue>& sv = mData.valueAt(index);
return sv.indexOf(value) >= 0;
}
@@ -102,7 +107,7 @@
return true;
}
-const SortedVector<uint32_t>* ResourceFilter::configsForAxis(int axis) const
+const SortedVector<AxisValue>* ResourceFilter::configsForAxis(int axis) const
{
ssize_t index = mData.indexOfKey(axis);
if (index < 0) {
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index 647b7bb..0d127ba 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -19,14 +19,15 @@
ResourceFilter() : mData(), mContainsPseudo(false) {}
status_t parse(const char* arg);
bool isEmpty() const;
- bool match(int axis, uint32_t value) const;
bool match(int axis, const ResTable_config& config) const;
bool match(const ResTable_config& config) const;
- const SortedVector<uint32_t>* configsForAxis(int axis) const;
+ const SortedVector<AxisValue>* configsForAxis(int axis) const;
inline bool containsPseudo() const { return mContainsPseudo; }
private:
- KeyedVector<int,SortedVector<uint32_t> > mData;
+ bool match(int axis, const AxisValue& value) const;
+
+ KeyedVector<int,SortedVector<AxisValue> > mData;
bool mContainsPseudo;
};
diff --git a/tools/aapt/ResourceIdCache.h b/tools/aapt/ResourceIdCache.h
index 65f7781..e6bcda2 100644
--- a/tools/aapt/ResourceIdCache.h
+++ b/tools/aapt/ResourceIdCache.h
@@ -7,7 +7,6 @@
#define RESOURCE_ID_CACHE_H
namespace android {
-class android::String16;
class ResourceIdCache {
public:
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 02a74b1..aff0088 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1292,8 +1292,8 @@
curIsStyled = true;
} else if (strcmp16(block.getElementName(&len), string16.string()) == 0) {
// Note the existence and locale of every string we process
- char rawLocale[16];
- curParams.getLocale(rawLocale);
+ char rawLocale[RESTABLE_MAX_LOCALE_LEN];
+ curParams.getBcp47Locale(rawLocale);
String8 locale(rawLocale);
String16 name;
String16 translatable;
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index ed497a5..1fa9615 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -33,6 +33,8 @@
built_ext_dep := $(call java-lib-deps,ext)
built_ext_classes := $(call java-lib-files,ext)
+built_ext_data := $(call intermediates-dir-for, \
+ JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
built_layoutlib_create_jar := $(call intermediates-dir-for, \
JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -60,7 +62,8 @@
$@ \
$(built_core_classes) \
$(built_framework_classes) \
- $(built_ext_classes)
+ $(built_ext_classes) \
+ $(built_ext_data)
$(hide) ls -l $(built_framework_classes)
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
index 62d0a0d..802cf1c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -20,6 +20,7 @@
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
+import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.List;
@@ -50,9 +51,12 @@
}
}
- /* package */ Graphics2D graphics;
- /* package */ Paint_Delegate paint;
- /* package */ char[] text;
+ private Graphics2D mGraphics;
+ private Paint_Delegate mPaint;
+ private char[] mText;
+ // Bounds of the text drawn so far.
+ private RectF mBounds;
+ private float mBaseline;
/**
* @param graphics May be null.
@@ -61,9 +65,9 @@
*/
/* package */ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
assert (paint != null);
- this.graphics = graphics;
- this.paint = paint;
- this.text = text;
+ mGraphics = graphics;
+ mPaint = paint;
+ mText = text;
}
/**
@@ -77,61 +81,62 @@
* @param advances If not null, then advances for each character to be rendered are returned
* here.
* @param advancesIndex index into advances from where the advances need to be filled.
- * @param draw If true and {@link graphics} is not null, draw the rendered text on the graphics
+ * @param draw If true and {@code graphics} is not null, draw the rendered text on the graphics
* at the given co-ordinates
* @param x The x-coordinate of the left edge of where the text should be drawn on the given
* graphics.
- * @param y The y-coordinate at which to draw the text on the given graphics.
- * @return The x-coordinate of the right edge of the drawn text. In other words,
- * x + the width of the text.
+ * @param y The y-coordinate at which to draw the text on the given mGraphics.
+ * @return A rectangle specifying the bounds of the text drawn.
*/
- /* package */ float renderText(int start, int limit, boolean isRtl, float advances[],
+ /* package */ RectF renderText(int start, int limit, boolean isRtl, float[] advances,
int advancesIndex, boolean draw, float x, float y) {
// We break the text into scripts and then select font based on it and then render each of
// the script runs.
- for (ScriptRun run : getScriptRuns(text, start, limit, isRtl, paint.getFonts())) {
+ mBounds = new RectF(x, y, x, y);
+ mBaseline = y;
+ for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mPaint.getFonts())) {
int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
- x = renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw,
- x, y);
+ renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw);
advancesIndex += run.limit - run.start;
}
- return x;
+ return mBounds;
}
/**
- * Render a script run. Use the preferred font to render as much as possible. This also
- * implements a fallback mechanism to render characters that cannot be drawn using the
- * preferred font.
- *
- * @return x + width of the text drawn.
+ * Render a script run to the right of the bounds passed. Use the preferred font to render as
+ * much as possible. This also implements a fallback mechanism to render characters that cannot
+ * be drawn using the preferred font.
*/
- private float renderScript(int start, int limit, FontInfo preferredFont, int flag,
- float advances[], int advancesIndex, boolean draw, float x, float y) {
- List<FontInfo> fonts = paint.getFonts();
+ private void renderScript(int start, int limit, FontInfo preferredFont, int flag,
+ float[] advances, int advancesIndex, boolean draw) {
+ List<FontInfo> fonts = mPaint.getFonts();
if (fonts == null || preferredFont == null) {
- return x;
+ return;
}
while (start < limit) {
boolean foundFont = false;
- int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(text, start, limit);
+ int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(mText, start, limit);
if (canDisplayUpTo == -1) {
- return render(start, limit, preferredFont, flag, advances, advancesIndex, draw,
- x, y);
- } else if (canDisplayUpTo > start) { // can draw something
- x = render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex,
- draw, x, y);
+ // We can draw all characters in the text.
+ render(start, limit, preferredFont, flag, advances, advancesIndex, draw);
+ return;
+ }
+ if (canDisplayUpTo > start) {
+ // We can draw something.
+ render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex, draw);
advancesIndex += canDisplayUpTo - start;
start = canDisplayUpTo;
}
- int charCount = Character.isHighSurrogate(text[start]) ? 2 : 1;
+ // The current character cannot be drawn with the preferred font. Cycle through all the
+ // fonts to check which one can draw it.
+ int charCount = Character.isHighSurrogate(mText[start]) ? 2 : 1;
for (FontInfo font : fonts) {
- canDisplayUpTo = font.mFont.canDisplayUpTo(text, start, start + charCount);
+ canDisplayUpTo = font.mFont.canDisplayUpTo(mText, start, start + charCount);
if (canDisplayUpTo == -1) {
- x = render(start, start+charCount, font, flag, advances, advancesIndex, draw,
- x, y);
+ render(start, start+charCount, font, flag, advances, advancesIndex, draw);
start += charCount;
advancesIndex += charCount;
foundFont = true;
@@ -143,46 +148,63 @@
// probably appear as a box or a blank space. We could, probably, use some
// heuristics and break the character into the base character and diacritics and
// then draw it, but it's probably not worth the effort.
- x = render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
- draw, x, y);
+ render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
+ draw);
start += charCount;
advancesIndex += charCount;
}
}
- return x;
}
/**
- * Render the text with the given font.
+ * Renders the text to the right of the bounds with the given font.
+ * @param font The font to render the text with.
*/
- private float render(int start, int limit, FontInfo font, int flag, float advances[],
- int advancesIndex, boolean draw, float x, float y) {
+ private void render(int start, int limit, FontInfo font, int flag, float[] advances,
+ int advancesIndex, boolean draw) {
- float totalAdvance = 0;
// Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with
// the anti-aliasing set.
FontRenderContext f = font.mMetrics.getFontRenderContext();
- FontRenderContext frc = new FontRenderContext(f.getTransform(), paint.isAntiAliased(),
+ FontRenderContext frc = new FontRenderContext(f.getTransform(), mPaint.isAntiAliased(),
f.usesFractionalMetrics());
- GlyphVector gv = font.mFont.layoutGlyphVector(frc, text, start, limit, flag);
+ GlyphVector gv = font.mFont.layoutGlyphVector(frc, mText, start, limit, flag);
int ng = gv.getNumGlyphs();
int[] ci = gv.getGlyphCharIndices(0, ng, null);
- for (int i = 0; i < ng; i++) {
- float adv = gv.getGlyphMetrics(i).getAdvanceX();
- if (advances != null) {
+ if (advances != null) {
+ for (int i = 0; i < ng; i++) {
int adv_idx = advancesIndex + ci[i];
- advances[adv_idx] += adv;
+ advances[adv_idx] += gv.getGlyphMetrics(i).getAdvanceX();
}
- totalAdvance += adv;
}
- if (draw && graphics != null) {
- graphics.drawGlyphVector(gv, x, y);
+ if (draw && mGraphics != null) {
+ mGraphics.drawGlyphVector(gv, mBounds.right, mBaseline);
}
- return x + totalAdvance;
+
+ // Update the bounds.
+ Rectangle2D awtBounds = gv.getLogicalBounds();
+ RectF bounds = awtRectToAndroidRect(awtBounds, mBounds.right, mBaseline);
+ // If the width of the bounds is zero, no text had been drawn earlier. Hence, use the
+ // coordinates from the bounds as an offset.
+ if (Math.abs(mBounds.right - mBounds.left) == 0) {
+ mBounds = bounds;
+ } else {
+ mBounds.union(bounds);
+ }
}
// --- Static helper methods ---
+ private static RectF awtRectToAndroidRect(Rectangle2D awtRec, float offsetX, float offsetY) {
+ float left = (float) awtRec.getX();
+ float top = (float) awtRec.getY();
+ float right = (float) (left + awtRec.getWidth());
+ float bottom = (float) (top + awtRec.getHeight());
+ RectF androidRect = new RectF(left, top, right, bottom);
+ androidRect.offset(offsetX, offsetY);
+ return androidRect;
+ }
+
/* package */ static List<ScriptRun> getScriptRuns(char[] text, int start, int limit,
boolean isRtl, List<FontInfo> fonts) {
LinkedList<ScriptRun> scriptRuns = new LinkedList<ScriptRun>();
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 602717b..1cc8ea5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -991,7 +991,8 @@
int limit = index + count;
boolean isRtl = flags == Canvas.DIRECTION_RTL;
if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
- float m = paintDelegate.measureText(text, index, count, isRtl);
+ RectF bounds = paintDelegate.measureText(text, index, count, isRtl);
+ float m = bounds.right - bounds.left;
if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
x -= m / 2;
} else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 38745ce..74b2893 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -176,7 +176,7 @@
/*package*/ static void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance,
long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
- (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(),
+ (int) loc.left, (int) loc.top, (int) loc.right, (int) loc.bottom,
bitmap_instance, chunk, paint_instance_or_null,
destDensity, srcDensity);
}
@@ -185,7 +185,7 @@
/*package*/ static void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance,
long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
- loc.left, loc.top, loc.width(), loc.height(),
+ loc.left, loc.top, loc.right, loc.bottom,
bitmap_instance, chunk, paint_instance_or_null,
destDensity, srcDensity);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index ca8e8aa..7007b71 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -575,7 +575,8 @@
return 0;
}
- return delegate.measureText(text, index, count, isRtl(bidiFlags));
+ RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags));
+ return bounds.right - bounds.left;
}
@LayoutlibDelegate
@@ -614,7 +615,8 @@
}
// measure from start to end
- float res = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+ RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
+ float res = bounds.right - bounds.left;
if (measuredWidth != null) {
measuredWidth[measureIndex] = res;
@@ -991,8 +993,9 @@
boolean isRtl = isRtl(flags);
int limit = index + count;
- return new BidiRenderer(null, delegate, text).renderText(
+ RectF bounds = new BidiRenderer(null, delegate, text).renderText(
index, limit, isRtl, advances, advancesIndex, false, 0, 0);
+ return bounds.right - bounds.left;
}
@LayoutlibDelegate
@@ -1058,9 +1061,7 @@
if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
return;
}
- int w = (int) delegate.measureText(text, index, count, isRtl(bidiFlags));
- int h= delegate.getFonts().get(0).mMetrics.getHeight();
- bounds.set(0, 0, w, h);
+ delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds);
}
@LayoutlibDelegate
@@ -1154,7 +1155,7 @@
}
}
- /*package*/ float measureText(char[] text, int index, int count, boolean isRtl) {
+ /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) {
return new BidiRenderer(null, this, text).renderText(
index, index + count, isRtl, null, 0, false, 0, 0);
}
diff --git a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
index 15cd687..320dd0d 100644
--- a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
@@ -17,6 +17,7 @@
package android.text.format;
import java.util.Calendar;
+import java.util.TimeZone;
import java.util.UnknownFormatConversionException;
import java.util.regex.Pattern;
@@ -35,6 +36,28 @@
// Regex to match odd number of '%'.
private static final Pattern p = Pattern.compile("(?<!%)(%%)*%(?!%)");
+ // Format used by toString()
+ private static final String FORMAT = "%1$tY%1$tm%1$tdT%1$tH%1$tM%1$tS<%1$tZ>";
+
+ @LayoutlibDelegate
+ /*package*/ static long normalize(Time thisTime, boolean ignoreDst) {
+ long millis = toMillis(thisTime, ignoreDst);
+ set(thisTime, millis);
+ return millis;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void switchTimezone(Time thisTime, String timezone) {
+ Calendar c = timeToCalendar(thisTime);
+ c.setTimeZone(TimeZone.getTimeZone(timezone));
+ calendarToTime(c, thisTime);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCompare(Time a, Time b) {
+ return timeToCalendar(a).compareTo(timeToCalendar(b));
+ }
+
@LayoutlibDelegate
/*package*/ static String format1(Time thisTime, String format) {
@@ -46,16 +69,92 @@
// of $.
return String.format(
p.matcher(format).replaceAll("$0\\1\\$t"),
- timeToCalendar(thisTime, Calendar.getInstance()));
+ timeToCalendar(thisTime));
} catch (UnknownFormatConversionException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_STRFTIME, "Unrecognized format", e, format);
return format;
}
}
- private static Calendar timeToCalendar(Time time, Calendar calendar) {
+ /**
+ * Return the current time in YYYYMMDDTHHMMSS<tz> format
+ */
+ @LayoutlibDelegate
+ /*package*/ static String toString(Time thisTime) {
+ Calendar c = timeToCalendar(thisTime);
+ return String.format(FORMAT, c);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeParse(Time thisTime, String s) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "android.text.format.Time.parse() not supported.", null);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeParse3339(Time thisTime, String s) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "android.text.format.Time.parse3339() not supported.", null);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setToNow(Time thisTime) {
+ calendarToTime(getCalendarInstance(thisTime), thisTime);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long toMillis(Time thisTime, boolean ignoreDst) {
+ // TODO: Respect ignoreDst.
+ return timeToCalendar(thisTime).getTimeInMillis();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void set(Time thisTime, long millis) {
+ Calendar c = getCalendarInstance(thisTime);
+ c.setTimeInMillis(millis);
+ calendarToTime(c,thisTime);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String format2445(Time thisTime) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "android.text.format.Time.format2445() not supported.", null);
+ return "";
+ }
+
+ // ---- private helper methods ----
+
+ private static Calendar timeToCalendar(Time time) {
+ Calendar calendar = getCalendarInstance(time);
calendar.set(time.year, time.month, time.monthDay, time.hour, time.minute, time.second);
return calendar;
}
+ private static void calendarToTime(Calendar c, Time time) {
+ time.timezone = c.getTimeZone().getID();
+ time.set(c.get(Calendar.SECOND), c.get(Calendar.MINUTE), c.get(Calendar.HOUR_OF_DAY),
+ c.get(Calendar.DATE), c.get(Calendar.MONTH), c.get(Calendar.YEAR));
+ time.weekDay = c.get(Calendar.DAY_OF_WEEK);
+ time.yearDay = c.get(Calendar.DAY_OF_YEAR);
+ time.isDst = c.getTimeZone().inDaylightTime(c.getTime()) ? 1 : 0;
+ // gmtoff is in seconds and TimeZone.getOffset() returns milliseconds.
+ time.gmtoff = c.getTimeZone().getOffset(c.getTimeInMillis()) / DateUtils.SECOND_IN_MILLIS;
+ }
+
+ /**
+ * Return a calendar instance with the correct timezone.
+ *
+ * @param time Time to obtain the timezone from.
+ */
+ private static Calendar getCalendarInstance(Time time) {
+ // TODO: Check platform code to make sure the behavior is same for null/invalid timezone.
+ if (time == null || time.timezone == null) {
+ // Default to local timezone.
+ return Calendar.getInstance();
+ }
+ // If timezone is invalid, use GMT.
+ return Calendar.getInstance(TimeZone.getTimeZone(time.timezone));
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 57771e3..377d996 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -334,7 +334,7 @@
backgroundView = backgroundLayout;
backgroundLayout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ LayoutParams.MATCH_PARENT, 0);
layoutParams.weight = 1;
backgroundLayout.setLayoutParams(layoutParams);
topLayout.addView(backgroundLayout);
@@ -369,7 +369,7 @@
// content frame
mContentRoot = new FrameLayout(context);
layoutParams = new LinearLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ LayoutParams.MATCH_PARENT, 0);
layoutParams.weight = 1;
mContentRoot.setLayoutParams(layoutParams);
backgroundLayout.addView(mContentRoot);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 1572a40..9a31705 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -29,6 +29,7 @@
import org.objectweb.asm.signature.SignatureVisitor;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
@@ -60,6 +61,9 @@
private final String[] mIncludeGlobs;
/** The set of classes to exclude.*/
private final Set<String> mExcludedClasses;
+ /** Glob patterns of files to keep as is. */
+ private final String[] mIncludeFileGlobs;
+ /** Copy these files into the output as is. */
/**
* Creates a new analyzer.
@@ -70,15 +74,19 @@
* @param deriveFrom Keep all classes that derive from these one (these included).
* @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*"
* ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is)
+ * @param includeFileGlobs Glob patterns of files which are kept as is. This is only for files
+ * not ending in .class.
*/
public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen,
- String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses) {
+ String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses,
+ String[] includeFileGlobs) {
mLog = log;
mGen = gen;
mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>();
mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0];
mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0];
mExcludedClasses = excludeClasses;
+ mIncludeFileGlobs = includeFileGlobs != null ? includeFileGlobs : new String[0];
}
/**
@@ -86,7 +94,11 @@
* Fills the generator with classes & dependencies found.
*/
public void analyze() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar);
+
+ TreeMap<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ parseZip(mOsSourceJar, zipClasses, filesFound);
mLog.info("Found %d classes in input JAR%s.", zipClasses.size(),
mOsSourceJar.size() > 1 ? "s" : "");
@@ -96,15 +108,29 @@
if (mGen != null) {
mGen.setKeep(found);
mGen.setDeps(deps);
+ mGen.setCopyFiles(filesFound);
}
}
/**
- * Parses a JAR file and returns a list of all classes founds using a map
- * class name => ASM ClassReader. Class names are in the form "android.view.View".
+ * Parses a JAR file and adds all the classes found to <code>classes</code>
+ * and all other files to <code>filesFound</code>.
+ *
+ * @param classes The map of class name => ASM ClassReader. Class names are
+ * in the form "android.view.View".
+ * @param fileFound The map of file name => InputStream. The file name is
+ * in the form "android/data/dataFile".
*/
- Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException {
- TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+ void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
+ Map<String, InputStream> filesFound) throws IOException {
+ if (classes == null || filesFound == null) {
+ return;
+ }
+
+ Pattern[] includeFilePatterns = new Pattern[mIncludeFileGlobs.length];
+ for (int i = 0; i < mIncludeFileGlobs.length; ++i) {
+ includeFilePatterns[i] = getPatternFromGlob(mIncludeFileGlobs[i]);
+ }
for (String jarPath : jarPathList) {
ZipFile zip = new ZipFile(jarPath);
@@ -116,11 +142,17 @@
ClassReader cr = new ClassReader(zip.getInputStream(entry));
String className = classReaderToClassName(cr);
classes.put(className, cr);
+ } else {
+ for (int i = 0; i < includeFilePatterns.length; ++i) {
+ if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
+ filesFound.put(entry.getName(), zip.getInputStream(entry));
+ break;
+ }
+ }
}
}
}
- return classes;
}
/**
@@ -202,7 +234,19 @@
*/
void findGlobs(String globPattern, Map<String, ClassReader> zipClasses,
Map<String, ClassReader> inOutFound) throws LogAbortException {
- // transforms the glob pattern in a regexp:
+
+ Pattern regexp = getPatternFromGlob(globPattern);
+
+ for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
+ String class_name = entry.getKey();
+ if (regexp.matcher(class_name).matches()) {
+ findClass(class_name, zipClasses, inOutFound);
+ }
+ }
+ }
+
+ Pattern getPatternFromGlob(String globPattern) {
+ // transforms the glob pattern in a regexp:
// - escape "." with "\."
// - replace "*" by "[^.]*"
// - escape "$" with "\$"
@@ -216,14 +260,7 @@
globPattern = globPattern.replaceAll("@", ".*");
globPattern += "$";
- Pattern regexp = Pattern.compile(globPattern);
-
- for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
- String class_name = entry.getKey();
- if (regexp.matcher(class_name).matches()) {
- findClass(class_name, zipClasses, inOutFound);
- }
- }
+ return Pattern.compile(globPattern);
}
/**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index b102561..207d8ae 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -20,6 +20,7 @@
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
+import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -52,6 +53,8 @@
private Map<String, ClassReader> mKeep;
/** All dependencies that must be completely stubbed. */
private Map<String, ClassReader> mDeps;
+ /** All files that are to be copied as-is. */
+ private Map<String, InputStream> mCopyFiles;
/** Counter of number of classes renamed during transform. */
private int mRenameCount;
/** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
@@ -195,6 +198,11 @@
mDeps = deps;
}
+ /** Sets the map of files to output as-is. */
+ public void setCopyFiles(Map<String, InputStream> copyFiles) {
+ mCopyFiles = copyFiles;
+ }
+
/** Gets the map of classes to output as-is, except if they have native methods */
public Map<String, ClassReader> getKeep() {
return mKeep;
@@ -205,6 +213,11 @@
return mDeps;
}
+ /** Gets the map of files to output as-is. */
+ public Map<String, InputStream> getCopyFiles() {
+ return mCopyFiles;
+ }
+
/** Generates the final JAR */
public void generate() throws FileNotFoundException, IOException {
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
@@ -232,6 +245,15 @@
all.put(name, b);
}
+ for (Entry<String, InputStream> entry : mCopyFiles.entrySet()) {
+ try {
+ byte[] b = inputStreamToByteArray(entry.getValue());
+ all.put(entry.getKey(), b);
+ } catch (IOException e) {
+ // Ignore.
+ }
+
+ }
mLog.info("# deps classes: %d", mDeps.size());
mLog.info("# keep classes: %d", mKeep.size());
mLog.info("# renamed : %d", mRenameCount);
@@ -381,4 +403,13 @@
return cv.hasNativeMethods();
}
+ private byte[] inputStreamToByteArray(InputStream is) throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ byte[] data = new byte[8192]; // 8KB
+ int n;
+ while ((n = is.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, n);
+ }
+ return buffer.toByteArray();
+ }
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index f6779e3..79aa642 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -131,7 +131,6 @@
"android.os.HandlerThread#run",
"android.os.Build#getString",
"android.text.format.DateFormat#is24HourFormat",
- "android.text.format.Time#format1",
"android.view.Choreographer#getRefreshRate",
"android.view.Display#updateDisplayInfoLocked",
"android.view.LayoutInflater#rInflate",
@@ -188,6 +187,7 @@
"android.graphics.Xfermode",
"android.os.SystemClock",
"android.text.AndroidBidi",
+ "android.text.format.Time",
"android.util.FloatMath",
"android.view.Display",
"libcore.icu.DateIntervalFormat",
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index ee501d2..a79fba1 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -115,7 +115,10 @@
"android.database.ContentObserver", // for Digital clock
"com.android.i18n.phonenumbers.*", // for TextView with autolink attribute
},
- excludeClasses);
+ excludeClasses,
+ new String[] {
+ "com/android/i18n/phonenumbers/data/*",
+ });
aa.analyze();
agen.generate();
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 005fc9d..7ec0d38 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -29,6 +29,7 @@
import org.objectweb.asm.ClassReader;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
@@ -55,8 +56,10 @@
Set<String> excludeClasses = new HashSet<String>(1);
excludeClasses.add("java.lang.JavaClass");
- mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */,
- null /* deriveFrom */, null /* includeGlobs */, excludeClasses);
+
+ String[] includeFiles = new String[]{"mock_android/data/data*"};
+ mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */,
+ null /* includeGlobs */, excludeClasses, includeFiles);
}
@After
@@ -65,7 +68,11 @@
@Test
public void testParseZip() throws IOException {
- Map<String, ClassReader> map = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> map = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, map, filesFound);
assertArrayEquals(new String[] {
"java.lang.JavaClass",
@@ -86,11 +93,17 @@
"mock_android.widget.TableLayout$LayoutParams"
},
map.keySet().toArray());
+ assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+ filesFound.keySet().toArray());
}
@Test
public void testFindClass() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
@@ -105,7 +118,11 @@
@Test
public void testFindGlobs() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
// this matches classes, a package match returns nothing
@@ -164,7 +181,11 @@
@Test
public void testFindClassesDerivingFrom() throws LogAbortException, IOException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
@@ -186,7 +207,11 @@
@Test
public void testDependencyVisitor() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 8a27173..0dbc238 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -33,6 +33,7 @@
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -131,7 +132,8 @@
new String[] { // include classes
"**"
},
- new HashSet<String>(0) /* excluded classes */);
+ new HashSet<String>(0) /* excluded classes */,
+ new String[]{} /* include files */);
aa.analyze();
agen.generate();
@@ -195,10 +197,15 @@
new String[] { // include classes
"**"
},
- new HashSet<String>(1));
+ new HashSet<String>(1),
+ new String[] { /* include files */
+ "mock_android/data/data*"
+ });
aa.analyze();
agen.generate();
- Map<String, ClassReader> output = parseZip(mOsDestJar);
+ Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+ parseZip(mOsDestJar, output, filesFound);
boolean injectedClassFound = false;
for (ClassReader cr: output.values()) {
TestClassVisitor cv = new TestClassVisitor();
@@ -206,10 +213,13 @@
injectedClassFound |= cv.mInjectedClassFound;
}
assertTrue(injectedClassFound);
+ assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+ filesFound.keySet().toArray());
}
- private Map<String,ClassReader> parseZip(String jarPath) throws IOException {
- TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+ private void parseZip(String jarPath,
+ Map<String, ClassReader> classes,
+ Map<String, InputStream> filesFound) throws IOException {
ZipFile zip = new ZipFile(jarPath);
Enumeration<? extends ZipEntry> entries = zip.entries();
@@ -220,10 +230,11 @@
ClassReader cr = new ClassReader(zip.getInputStream(entry));
String className = classReaderToClassName(cr);
classes.put(className, cr);
+ } else {
+ filesFound.put(entry.getName(), zip.getInputStream(entry));
}
}
- return classes;
}
private String classReaderToClassName(ClassReader classReader) {
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index 60d8efb..8dd0481 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
new file mode 100644
index 0000000..ab29fbe
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
@@ -0,0 +1 @@
+A simple data file that should *not* be copied to the output jar.
\ No newline at end of file
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
new file mode 100644
index 0000000..9b01893
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
@@ -0,0 +1 @@
+A simple data file that should be copied to the output jar unchanged.
\ No newline at end of file